Nice. Up to 85.55 C / 157.52 asm. Is now definatly better code than gbdk.
[fw/sdcc] / src / z80 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - Z80 specific code generator.
3
4   Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
5                                                 ticks   dhry    size
6   Base with asm strcpy / strcmp / memcpy:       23198   141     1A14
7   Improved WORD push                            22784   144     19AE
8   With label1 on                                22694   144     197E
9   With label2 on                                22743   144     198A
10   With label3 on                                22776   144     1999
11   With label4 on                                22776   144     1999
12   With all 'label' on                           22661   144     196F
13   With loopInvariant on                         20919   156     19AB
14   With loopInduction on                         Breaks          198B
15   With all working on                           20796   158     196C
16   Slightly better genCmp(signed)                20597   159     195B
17   Better reg packing, first peephole            20038   163     1873
18   With assign packing                           19281   165     1849
19
20   Michael Hope <michaelh@earthling.net> 2000
21   Based on the mcs51 generator - Sandeep Dutta . sandeep.dutta@usa.net (1998)
22                            and -  Jean-Louis VERN.jlvern@writeme.com (1999)
23          
24   This program is free software; you can redistribute it and/or modify it
25   under the terms of the GNU General Public License as published by the
26   Free Software Foundation; either version 2, or (at your option) any
27   later version.
28   
29   This program is distributed in the hope that it will be useful,
30   but WITHOUT ANY WARRANTY; without even the implied warranty of
31   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32   GNU General Public License for more details.
33   
34   You should have received a copy of the GNU General Public License
35   along with this program; if not, write to the Free Software
36   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37   
38   In other words, you are welcome to use, share and improve this program.
39   You are forbidden to forbid anyone else to use, share and improve
40   what you give them.   Help stamp out software-hoarding!
41
42 -------------------------------------------------------------------------*/
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <ctype.h>
48
49 #ifdef HAVE_SYS_ISA_DEFS_H
50 #include <sys/isa_defs.h>
51 #endif
52
53 #include "z80.h"
54 #include "SDCCpeeph.h"
55 #include "gen.h"
56 #include "SDCCglue.h"
57
58 /* this is the down and dirty file with all kinds of kludgy & hacky
59    stuff. This is what it is all about CODE GENERATION for a specific MCU.
60    Some of the routines may be reusable, will have to see */
61
62 static char *zero = "#0x00";
63 static char *one  = "#0x01";
64 static char *spname ;
65 static char *_z80_return[] = {"l", "h", "e", "d" };
66 static char *_gbz80_return[] = { "e", "d", "l", "h" };
67 static char **_fReturn;
68 static char **_fTmp;
69
70 static char *accUse[] = {"a" };
71 short rbank = -1;
72 short accInUse = 0 ;
73 short inLine = 0;
74 short debugLine = 0;
75 short nregssaved = 0;
76 extern int ptrRegReq ;
77 extern int nRegs;
78 extern FILE *codeOutFile;
79 set *sendSet = NULL;
80 const char *_shortJP = "jp";
81
82 #define RESULTONSTACK(x) \
83                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
84                          IC_RESULT(x)->aop->type == AOP_STK )
85
86 #define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
87 #define CLRC    emitcode("xor","a,a");
88
89 #define LABEL_STR       "%05d$"
90
91 lineNode *lineHead = NULL;
92 lineNode *lineCurr = NULL;
93
94 unsigned char   SLMask[] = {0xFF ,0xFE, 0xFC, 0xF8, 0xF0,
95 0xE0, 0xC0, 0x80, 0x00};
96 unsigned char   SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
97 0x07, 0x03, 0x01, 0x00};
98
99 static int _lastStack = 0;
100 static int _pushed = 0;
101 static int _spoffset;
102 static int _lastHLOff = 0;
103 static asmop *_lastHL;
104
105 #define LSB     0
106 #define MSB16   1
107 #define MSB24   2
108 #define MSB32   3
109
110 /* Stack frame:
111
112    IX+4         param0  LH
113    IX+2         ret     LH
114    IX+0         ix      LH
115    IX-2         temp0   LH
116 */
117
118 /*-----------------------------------------------------------------*/
119 /* emitcode - writes the code into a file : for now it is simple    */
120 /*-----------------------------------------------------------------*/
121 void emitcode (const char *inst, const char *fmt, ...)
122 {
123     va_list ap;
124     char lb[MAX_INLINEASM];  
125     char *lbp = lb;
126
127     va_start(ap,fmt);   
128
129     if (*inst != '\0') {
130         sprintf(lb,"%s\t",inst);
131         vsprintf(lb+(strlen(lb)),fmt,ap);
132     }  else 
133         vsprintf(lb,fmt,ap);
134
135     while (isspace(*lbp)) lbp++;
136
137     if (lbp && *lbp) 
138         lineCurr = (lineCurr ?
139                     connectLine(lineCurr,newLineNode(lb)) :
140                     (lineHead = newLineNode(lb)));
141     lineCurr->isInline = inLine;
142     lineCurr->isDebug  = debugLine;
143     va_end(ap);
144 }
145
146 const char *getPairName(asmop *aop)
147 {
148     if (aop->type == AOP_REG) {
149         switch (aop->aopu.aop_reg[0]->rIdx) {
150         case C_IDX:
151             return "bc";
152             break;
153         case E_IDX:
154             return "de";
155             break;
156         case L_IDX:
157             return "hl";
158             break;
159         }
160     }
161     else if (aop->type == AOP_STR) {
162         switch (*aop->aopu.aop_str[0]) {
163         case 'c':
164             return "bc";
165             break;
166         case 'e':
167             return "de";
168             break;
169         case 'l':
170             return "hl";
171             break;
172         }
173     }
174     assert(0);
175     return NULL;
176 }
177
178 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
179 bool isPair(asmop *aop)
180 {
181     if (aop->size == 2) {
182         if (aop->type == AOP_REG) {
183             if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) {
184                 return TRUE;
185             }
186             if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) {
187                 return TRUE;
188             }
189             if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) {
190                 return TRUE;
191             }
192         }
193         if (aop->type == AOP_STR) {
194             if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) {
195                 return TRUE;
196             }
197             if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) {
198                 return TRUE;
199             }
200             if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) {
201                 return TRUE;
202             }
203         }
204     }
205     return FALSE;
206 }
207
208 /** Push a register pair onto the stack */
209 void genPairPush(asmop *aop)
210 {
211     emitcode("push", "%s", getPairName(aop));
212 }
213
214 /*-----------------------------------------------------------------*/
215 /* newAsmop - creates a new asmOp                                  */
216 /*-----------------------------------------------------------------*/
217 static asmop *newAsmop (short type)
218 {
219     asmop *aop;
220
221     ALLOC(aop,sizeof(asmop));
222     aop->type = type;
223     return aop;
224 }
225
226 /*-----------------------------------------------------------------*/
227 /* aopForSym - for a true symbol                                   */
228 /*-----------------------------------------------------------------*/
229 static asmop *aopForSym (iCode *ic,symbol *sym,bool result)
230 {
231     asmop *aop;
232     memmap *space= SPEC_OCLS(sym->etype);
233
234     /* if already has one */
235     if (sym->aop)
236         return sym->aop;
237
238     /* Assign depending on the storage class */
239     if (sym->onStack || sym->iaccess) {
240         sym->aop = aop = newAsmop(AOP_STK);
241         aop->size = getSize(sym->type);
242         _lastHL = NULL;
243         aop->aopu.aop_stk = sym->stack;
244         return aop;
245     }
246
247     /* special case for a function */
248     if (IS_FUNC(sym->type)) {   
249         sym->aop = aop = newAsmop(AOP_IMMD);    
250         ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
251         strcpy(aop->aopu.aop_immd,sym->rname);
252         aop->size = 2;
253         return aop;
254     }
255
256 #if 0
257     if (IS_GB) {
258         /* if it is in direct space */
259         if (IN_DIRSPACE(space)) {
260             sym->aop = aop = newAsmop (AOP_DIR);
261             aop->aopu.aop_dir = sym->rname ;
262             aop->size = getSize(sym->type);
263             emitcode("", "; AOP_DIR for %s", sym->rname);
264             return aop;
265         }
266     }
267 #endif
268
269     /* only remaining is far space */
270     /* in which case DPTR gets the address */
271     if (IS_GB) {
272         sym->aop = aop = newAsmop(AOP_HL);
273         _lastHL = NULL;
274     }
275     else {
276         sym->aop = aop = newAsmop(AOP_IY);
277         emitcode ("ld","iy,#%s ; a", sym->rname);
278     }
279     aop->size = getSize(sym->type);
280     aop->aopu.aop_dir = sym->rname;
281
282     /* if it is in code space */
283     if (IN_CODESPACE(space))
284         aop->code = 1;
285
286     return aop;     
287 }
288
289 /*-----------------------------------------------------------------*/
290 /* aopForRemat - rematerialzes an object                           */
291 /*-----------------------------------------------------------------*/
292 static asmop *aopForRemat (symbol *sym)
293 {
294     char *s = buffer;   
295     iCode *ic = sym->rematiCode;
296     asmop *aop = newAsmop(AOP_IMMD);
297
298     while (1) {
299         /* if plus or minus print the right hand side */
300         if (ic->op == '+' || ic->op == '-') {
301             sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
302                     ic->op );
303             s += strlen(s);
304             ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
305             continue ;
306         }
307         /* we reached the end */
308         sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname);
309         break;
310     }
311
312     ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
313     strcpy(aop->aopu.aop_immd,buffer);    
314     return aop;        
315 }
316
317 /*-----------------------------------------------------------------*/
318 /* regsInCommon - two operands have some registers in common       */
319 /*-----------------------------------------------------------------*/
320 bool regsInCommon (operand *op1, operand *op2)
321 {
322     symbol *sym1, *sym2;
323     int i;
324
325     /* if they have registers in common */
326     if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
327         return FALSE ;
328
329     sym1 = OP_SYMBOL(op1);
330     sym2 = OP_SYMBOL(op2);
331
332     if (sym1->nRegs == 0 || sym2->nRegs == 0)
333         return FALSE ;
334
335     for (i = 0 ; i < sym1->nRegs ; i++) {
336         int j;
337         if (!sym1->regs[i])
338             continue ;
339
340         for (j = 0 ; j < sym2->nRegs ;j++ ) {
341             if (!sym2->regs[j])
342                 continue ;
343
344             if (sym2->regs[j] == sym1->regs[i])
345                 return TRUE ;
346         }
347     }
348
349     return FALSE ;
350 }
351
352 /*-----------------------------------------------------------------*/
353 /* operandsEqu - equivalent                                        */
354 /*-----------------------------------------------------------------*/
355 bool operandsEqu ( operand *op1, operand *op2)
356 {
357     symbol *sym1, *sym2;
358
359     /* if they not symbols */
360     if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
361         return FALSE;
362
363     sym1 = OP_SYMBOL(op1);
364     sym2 = OP_SYMBOL(op2);
365
366     /* if both are itemps & one is spilt
367        and the other is not then false */
368     if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
369         sym1->isspilt != sym2->isspilt )
370         return FALSE ;
371
372     /* if they are the same */
373     if (sym1 == sym2)
374         return 1;
375
376     if (strcmp(sym1->rname,sym2->rname) == 0)
377         return 2;
378
379
380     /* if left is a tmp & right is not */
381     if (IS_ITEMP(op1)  && 
382         !IS_ITEMP(op2) &&
383         sym1->isspilt  &&
384         (sym1->usl.spillLoc == sym2))
385         return 3;
386
387     if (IS_ITEMP(op2)  && 
388         !IS_ITEMP(op1) &&
389         sym2->isspilt  &&
390         sym1->level > 0 &&
391         (sym2->usl.spillLoc == sym1))
392         return 4;
393
394     return FALSE;
395 }
396
397 /*-----------------------------------------------------------------*/
398 /* sameRegs - two asmops have the same registers                   */
399 /*-----------------------------------------------------------------*/
400 bool sameRegs (asmop *aop1, asmop *aop2 )
401 {
402     int i;
403
404     if (aop1 == aop2)
405         return TRUE ;
406
407     if (aop1->type != AOP_REG ||
408         aop2->type != AOP_REG )
409         return FALSE ;
410
411     if (aop1->size != aop2->size)
412         return FALSE ;
413
414     for (i = 0 ; i < aop1->size ; i++ )
415         if (aop1->aopu.aop_reg[i] !=
416             aop2->aopu.aop_reg[i] )
417             return FALSE ;
418
419     return TRUE ;
420 }
421
422 /*-----------------------------------------------------------------*/
423 /* aopOp - allocates an asmop for an operand  :                    */
424 /*-----------------------------------------------------------------*/
425 static void aopOp (operand *op, iCode *ic, bool result)
426 {
427     asmop *aop;
428     symbol *sym;
429     int i;
430
431     if (!op)
432         return ;
433
434     /* if this a literal */
435     if (IS_OP_LITERAL(op)) {
436         op->aop = aop = newAsmop(AOP_LIT);
437         aop->aopu.aop_lit = op->operand.valOperand;
438         aop->size = getSize(operandType(op));
439         return;
440     }
441
442     /* if already has a asmop then continue */
443     if (op->aop)
444         return ;
445
446     /* if the underlying symbol has a aop */
447     if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
448         op->aop = OP_SYMBOL(op)->aop;
449         return;
450     }
451
452     /* if this is a true symbol */
453     if (IS_TRUE_SYMOP(op)) {    
454         op->aop = aopForSym(ic,OP_SYMBOL(op),result);
455         return ;
456     }
457
458     /* this is a temporary : this has
459     only four choices :
460     a) register
461     b) spillocation
462     c) rematerialize 
463     d) conditional   
464     e) can be a return use only */
465
466     sym = OP_SYMBOL(op);
467
468     /* if the type is a conditional */
469     if (sym->regType == REG_CND) {
470         aop = op->aop = sym->aop = newAsmop(AOP_CRY);
471         aop->size = 0;
472         return;
473     }
474
475     /* if it is spilt then two situations
476     a) is rematerialize 
477     b) has a spill location */
478     if (sym->isspilt || sym->nRegs == 0) {
479         /* rematerialize it NOW */
480         if (sym->remat) {
481             sym->aop = op->aop = aop =
482                                       aopForRemat (sym);
483             aop->size = getSize(sym->type);
484             return;
485         }
486
487         if (sym->accuse) {
488             int i;
489             aop = op->aop = sym->aop = newAsmop(AOP_ACC);
490             aop->size = getSize(sym->type);
491             for ( i = 0 ; i < 2 ; i++ )
492                 aop->aopu.aop_str[i] = accUse[i];
493             return;  
494         }
495
496         if (sym->ruonly ) {
497             int i;
498             aop = op->aop = sym->aop = newAsmop(AOP_STR);
499             aop->size = getSize(sym->type);
500             for ( i = 0 ; i < 4 ; i++ )
501                 aop->aopu.aop_str[i] = _fReturn[i];
502             return;
503         }
504
505         /* else spill location  */
506         sym->aop = op->aop = aop = 
507                                   aopForSym(ic,sym->usl.spillLoc,result);
508         aop->size = getSize(sym->type);
509         return;
510     }
511
512     /* must be in a register */
513     sym->aop = op->aop = aop = newAsmop(AOP_REG);
514     aop->size = sym->nRegs;
515     for ( i = 0 ; i < sym->nRegs ;i++)
516         aop->aopu.aop_reg[i] = sym->regs[i];
517 }
518
519 /*-----------------------------------------------------------------*/
520 /* freeAsmop - free up the asmop given to an operand               */
521 /*----------------------------------------------------------------*/
522 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
523 {   
524     asmop *aop ;
525
526     if (!op)
527         aop = aaop;
528     else 
529         aop = op->aop;
530
531     if (!aop)
532         return ;
533
534     if (aop->freed)
535         goto dealloc; 
536
537     aop->freed = 1;
538
539     switch (aop->type) {
540     case AOP_STK :
541         break;
542     }
543
544 dealloc:
545     /* all other cases just dealloc */
546     if (op ) {
547         op->aop = NULL;
548         if (IS_SYMOP(op)) {
549             OP_SYMBOL(op)->aop = NULL;    
550             /* if the symbol has a spill */
551             if (SPIL_LOC(op))
552                 SPIL_LOC(op)->aop = NULL;
553         }
554     }
555 }
556
557 char *aopGetWordLong(asmop *aop, int offset, bool with_hash)
558 {
559     char *s = buffer ;
560     char *rs;
561
562     if (aop->size != 2)
563         return NULL;
564     assert(offset == 0);
565
566     /* depending on type */
567     switch (aop->type) {
568     case AOP_IMMD:
569         sprintf (s,"%s%s",with_hash ? "#" : "", aop->aopu.aop_immd);
570         ALLOC_ATOMIC(rs,strlen(s)+1);
571         strcpy(rs,s);   
572         return rs;
573         
574     case AOP_LIT: {
575         value * val = aop->aopu.aop_lit;
576         /* if it is a float then it gets tricky */
577         /* otherwise it is fairly simple */
578         if (!IS_FLOAT(val->type)) {
579             unsigned long v = floatFromVal(val);
580
581             sprintf(buffer,"%s0x%04lx", with_hash ? "#" : "", v);
582             ALLOC_ATOMIC(rs,strlen(buffer)+1);
583             return strcpy (rs,buffer);
584         }
585         assert(0);
586         return NULL;
587     }
588     }
589     return NULL;
590 }
591
592 char *aopGetWord(asmop *aop, int offset)
593 {
594     return aopGetWordLong(aop, offset, TRUE);
595 }
596
597 static void setupHL(asmop *aop, int offset)
598 {
599     if (_lastHL != aop) {
600         switch (aop->type) {
601         case AOP_HL:
602             emitcode("ld", "hl,#%s+%d", aop->aopu.aop_dir, offset);
603             break;
604         case AOP_STK:
605             /* In some cases we can still inc or dec hl */
606             emitcode("lda", "hl,%d+%d+%d(sp)", aop->aopu.aop_stk+offset, _pushed, _spoffset);
607             break;
608         default:
609             assert(0);
610         }
611         _lastHL = aop;
612         _lastHLOff = offset;
613     }
614     else {
615         while (offset < _lastHLOff) {
616             emitcode("dec", "hl");
617             _lastHLOff--;
618         }
619         while (offset > _lastHLOff) {
620             emitcode("inc", "hl");
621             _lastHLOff++;
622         }
623     }
624 }
625
626 /*-----------------------------------------------------------------*/
627 /* aopGet - for fetching value of the aop                          */
628 /*-----------------------------------------------------------------*/
629 static char *aopGet (asmop *aop, int offset, bool bit16)
630 {
631     char *s = buffer ;
632     char *rs;
633
634     /* offset is greater than size then zero */
635     if (offset > (aop->size - 1) &&
636         aop->type != AOP_LIT)
637         return zero;
638
639     /* depending on type */
640     switch (aop->type) {
641     case AOP_IMMD:
642         if (bit16) 
643             sprintf (s,"#%s",aop->aopu.aop_immd);
644         else
645             if (offset) {
646                 assert(offset == 1);
647                 sprintf(s,"#>%s",
648                         aop->aopu.aop_immd);
649             }
650             else
651                 sprintf(s,"#<%s",
652                         aop->aopu.aop_immd);
653         ALLOC_ATOMIC(rs,strlen(s)+1);
654         strcpy(rs,s);   
655         return rs;
656         
657     case AOP_DIR:
658         assert(IS_GB);
659         emitcode("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
660         sprintf(s, "a");
661         ALLOC_ATOMIC(rs,strlen(s)+1);
662         strcpy(rs,s);   
663         return rs;
664         
665     case AOP_REG:
666         return aop->aopu.aop_reg[offset]->name;
667
668     case AOP_HL:
669         assert(IS_GB);
670         setupHL(aop, offset);
671         sprintf(s, "(hl)");
672         ALLOC_ATOMIC(rs, strlen(s)+1);
673         strcpy(rs,s);
674         return rs;
675
676     case AOP_IY:
677         sprintf(s,"%d(iy)", offset);
678         ALLOC_ATOMIC(rs,strlen(s)+1);
679         strcpy(rs,s);   
680         return rs;
681
682     case AOP_STK:
683         if (IS_GB) {
684             setupHL(aop, offset);
685             sprintf(s, "(hl)");
686         }
687         else {
688             sprintf(s,"%d(ix) ; %u", aop->aopu.aop_stk+offset, offset);
689         }
690         ALLOC_ATOMIC(rs,strlen(s)+1);
691         strcpy(rs,s);   
692         return rs;
693         
694     case AOP_CRY:
695         assert(0);
696         
697     case AOP_ACC:
698         if (!offset) {
699             return "a";
700         }
701         return "#0x00";
702
703     case AOP_LIT:
704         return aopLiteral (aop->aopu.aop_lit,offset);
705         
706     case AOP_STR:
707         aop->coff = offset;
708         return aop->aopu.aop_str[offset];
709     }
710
711     fprintf(stderr, "Type %u\n", aop->type);
712
713     werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
714            "aopget got unsupported aop->type");
715     exit(0);
716 }
717
718 bool isRegString(char *s)
719 {
720     if (!strcmp(s, "b") ||
721         !strcmp(s, "c") ||
722         !strcmp(s, "d") ||
723         !strcmp(s, "e") ||
724         !strcmp(s, "a") ||
725         !strcmp(s, "h") ||
726         !strcmp(s, "l"))
727         return TRUE;
728     return FALSE;
729 }
730
731 bool isConstant(char *s)
732 {
733     return  (*s == '#');
734 }
735
736 bool canAssignToPtr(char *s)
737 {
738     if (isRegString(s))
739         return TRUE;
740     if (isConstant(s))
741         return TRUE;
742     return FALSE;
743 }
744
745 /*-----------------------------------------------------------------*/
746 /* aopPut - puts a string for a aop                                */
747 /*-----------------------------------------------------------------*/
748 static void aopPut (asmop *aop, char *s, int offset)
749 {
750     if (aop->size && offset > ( aop->size - 1)) {
751         werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
752                "aopPut got offset > aop->size");
753         exit(0);
754     }
755
756     /* will assign value to value */
757     /* depending on where it is ofcourse */
758     switch (aop->type) {
759     case AOP_DIR:
760         /* Direct.  Hmmm. */
761         assert(IS_GB);
762         emitcode("ld", "a,%s", s);
763         emitcode("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
764         break;
765         
766     case AOP_REG:
767         /* Dont bother if it's a ld x,x */
768         if (strcmp(aop->aopu.aop_reg[offset]->name,s) != 0) {
769             emitcode("ld","%s,%s",
770                      aop->aopu.aop_reg[offset]->name,s);
771         }
772         break;
773         
774     case AOP_IY:
775         assert(!IS_GB);
776         if (!canAssignToPtr(s)) {
777             emitcode("ld", "a,%s", s);
778             emitcode("ld", "%d(iy),a", offset);
779         }
780         else
781             emitcode("ld", "%d(iy),%s", offset, s);
782         break;
783     
784     case AOP_HL:
785         assert(IS_GB);
786         if (!strcmp(s, "(hl)")) {
787             emitcode("ld", "a,(hl)");
788             s = "a";
789         }
790         setupHL(aop, offset);
791         emitcode("ld", "(hl),%s", s);
792         break;
793
794     case AOP_STK:
795         if (IS_GB) {
796             if (!strcmp("(hl)", s)) {
797                 emitcode("ld", "a,(hl)");
798                 s = "a";
799             }
800             setupHL(aop, offset);
801             if (!canAssignToPtr(s)) {
802                 emitcode("ld", "a,%s", s);
803                 emitcode("ld", "(hl),a");
804             }
805             else
806                 emitcode("ld", "(hl),%s", s);
807         }
808         else {
809             if (!canAssignToPtr(s)) {
810                 emitcode("ld", "a,%s", s);
811                 emitcode("ld", "%d(ix),a", aop->aopu.aop_stk+offset);
812             }
813             else
814                 emitcode("ld", "%d(ix),%s", aop->aopu.aop_stk+offset, s);
815         }
816         break;
817         
818     case AOP_CRY:
819         /* if bit variable */
820         if (!aop->aopu.aop_dir) {
821             emitcode("ld", "a,#0");
822             emitcode("rla", "");
823         } else {
824             /* In bit space but not in C - cant happen */
825             assert(0);
826         }
827         break;
828         
829     case AOP_STR:
830         aop->coff = offset;
831         if (strcmp(aop->aopu.aop_str[offset],s)) {
832             emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
833         }
834         break;
835         
836     case AOP_ACC:
837         aop->coff = offset;
838         if (!offset && (strcmp(s,"acc") == 0))
839             break;
840         if (offset>0) {
841             
842             emitcode("", "; Error aopPut AOP_ACC");
843         }
844         else {
845             if (strcmp(aop->aopu.aop_str[offset],s))
846                 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
847         }
848         break;
849
850     default :
851         werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
852                "aopPut got unsupported aop->type");
853         exit(0);    
854     }    
855 }
856
857 #define AOP(op) op->aop
858 #define AOP_TYPE(op) AOP(op)->type
859 #define AOP_SIZE(op) AOP(op)->size
860 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
861
862 /*-----------------------------------------------------------------*/
863 /* getDataSize - get the operand data size                         */
864 /*-----------------------------------------------------------------*/
865 int getDataSize(operand *op)
866 {
867     int size;
868     size = AOP_SIZE(op);
869     if(size == 3) {
870         /* pointer */
871         assert(0);
872     }
873     return size;
874 }
875
876 /*-----------------------------------------------------------------*/
877 /* movLeft2Result - move byte from left to result                  */
878 /*-----------------------------------------------------------------*/
879 static void movLeft2Result (operand *left, int offl,
880                             operand *result, int offr, int sign)
881 {
882     char *l;
883     if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
884         l = aopGet(AOP(left),offl,FALSE);
885
886         if (!sign) {
887             aopPut(AOP(result),l,offr);
888         }
889         else {
890             assert(0);
891         }
892     }
893 }
894
895
896 /** Put Acc into a register set 
897  */
898 void outAcc(operand *result)
899 {
900     int size, offset;
901     size = getDataSize(result);
902     if (size){
903         aopPut(AOP(result),"a",0);
904         size--;
905         offset = 1;
906         /* unsigned or positive */
907         while (size--){
908             aopPut(AOP(result),zero,offset++);
909         }
910     }
911 }
912
913 /** Take the value in carry and put it into a register
914  */
915 void outBitC(operand *result)
916 {
917     /* if the result is bit */
918     if (AOP_TYPE(result) == AOP_CRY) {
919         emitcode("", "; Note: outBitC form 1");
920         aopPut(AOP(result),"blah",0);
921     }
922     else {
923         emitcode("ld", "a,#0");
924         emitcode("rla", "");
925         outAcc(result);
926     }
927 }
928
929 /*-----------------------------------------------------------------*/
930 /* toBoolean - emit code for orl a,operator(sizeop)                */
931 /*-----------------------------------------------------------------*/
932 void toBoolean(operand *oper)
933 {
934     int size = AOP_SIZE(oper);
935     int offset = 0;
936     if (size>1) {
937         emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
938         size--;
939         while (size--) 
940             emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
941     }
942     else {
943         if (AOP(oper)->type != AOP_ACC) {
944             CLRC;
945             emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
946         }
947     }
948 }
949
950 /*-----------------------------------------------------------------*/
951 /* genNot - generate code for ! operation                          */
952 /*-----------------------------------------------------------------*/
953 static void genNot (iCode *ic)
954 {
955     link *optype = operandType(IC_LEFT(ic));
956
957     /* assign asmOps to operand & result */
958     aopOp (IC_LEFT(ic),ic,FALSE);
959     aopOp (IC_RESULT(ic),ic,TRUE);
960
961     /* if in bit space then a special case */
962     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
963         assert(0);
964     }
965
966     /* if type float then do float */
967     if (IS_FLOAT(optype)) {
968         assert(0);
969     }
970
971     toBoolean(IC_LEFT(ic));
972
973     /* Not of A:
974        If A == 0, !A = 1
975        else A = 0
976        So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
977     emitcode("sub", "a,#0x01");
978     outBitC(IC_RESULT(ic));
979
980     /* release the aops */
981     freeAsmop(IC_LEFT(ic),NULL,ic);
982     freeAsmop(IC_RESULT(ic),NULL,ic);
983 }
984
985 /*-----------------------------------------------------------------*/
986 /* genCpl - generate code for complement                           */
987 /*-----------------------------------------------------------------*/
988 static void genCpl (iCode *ic)
989 {
990     int offset = 0;
991     int size ;
992
993
994     /* assign asmOps to operand & result */
995     aopOp (IC_LEFT(ic),ic,FALSE);
996     aopOp (IC_RESULT(ic),ic,TRUE);
997
998     /* if both are in bit space then 
999     a special case */
1000     if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1001         AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) { 
1002         assert(0);
1003     } 
1004
1005     size = AOP_SIZE(IC_RESULT(ic));
1006     while (size--) {
1007         char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1008         MOVA(l);       
1009         emitcode("cpl","");
1010         aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1011     }
1012
1013     /* release the aops */
1014     freeAsmop(IC_LEFT(ic),NULL,ic);
1015     freeAsmop(IC_RESULT(ic),NULL,ic);
1016 }
1017
1018 /*-----------------------------------------------------------------*/
1019 /* genUminus - unary minus code generation                         */
1020 /*-----------------------------------------------------------------*/
1021 static void genUminus (iCode *ic)
1022 {
1023     int offset ,size ;
1024     link *optype, *rtype;
1025
1026     /* assign asmops */
1027     aopOp(IC_LEFT(ic),ic,FALSE);
1028     aopOp(IC_RESULT(ic),ic,TRUE);
1029
1030     /* if both in bit space then special
1031     case */
1032     if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1033         AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) { 
1034         assert(0);
1035         goto release;
1036     } 
1037
1038     optype = operandType(IC_LEFT(ic));
1039     rtype = operandType(IC_RESULT(ic));
1040
1041     /* if float then do float stuff */
1042     if (IS_FLOAT(optype)) {
1043         assert(0);
1044         goto release;
1045     }
1046
1047     /* otherwise subtract from zero */
1048     size = AOP_SIZE(IC_LEFT(ic));
1049     offset = 0 ;
1050     CLRC ;
1051     while(size--) {
1052         char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
1053         emitcode("ld", "a,#0");
1054         emitcode("sbc","a,%s",l);
1055         aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1056     }
1057
1058     /* if any remaining bytes in the result */
1059     /* we just need to propagate the sign   */
1060     if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) {
1061         emitcode("rlc","a");
1062         emitcode("sbc","a,a");
1063         while (size--) 
1064             aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1065     }       
1066
1067 release:
1068     /* release the aops */
1069     freeAsmop(IC_LEFT(ic),NULL,ic);
1070     freeAsmop(IC_RESULT(ic),NULL,ic);
1071 }
1072
1073 static bool requiresHL(asmop *aop)
1074 {
1075     switch (aop->type) {
1076     case AOP_HL:
1077     case AOP_STK:
1078         return TRUE;
1079     default:
1080         return FALSE;
1081     }
1082 }
1083
1084 /*-----------------------------------------------------------------*/
1085 /* assignResultValue -                                             */
1086 /*-----------------------------------------------------------------*/
1087 void assignResultValue(operand * oper)
1088 {
1089     int offset = 0;
1090     int size = AOP_SIZE(oper);
1091
1092     assert(size <= 2);
1093
1094     while (size--) {
1095         aopPut(AOP(oper),_fReturn[offset],offset);
1096         offset++;
1097     }
1098 }
1099
1100 static void fetchHL(asmop *aop)
1101 {
1102     if (IS_GB && requiresHL(aop)) {
1103         aopGet(aop, 0, FALSE);
1104         emitcode("ld", "a,(hl+)");
1105         emitcode("ld", "h,(hl)");
1106         emitcode("ld", "l,a");
1107     }
1108     else {
1109         emitcode("ld", "l,%s", aopGet(aop, 0, FALSE));
1110         emitcode("ld", "h,%s", aopGet(aop, 1, FALSE));
1111     }
1112 }
1113
1114 /*-----------------------------------------------------------------*/
1115 /* genIpush - genrate code for pushing this gets a little complex  */
1116 /*-----------------------------------------------------------------*/
1117 static void genIpush (iCode *ic)
1118 {
1119     int size, offset = 0 ;
1120     char *l;
1121
1122
1123     /* if this is not a parm push : ie. it is spill push 
1124        and spill push is always done on the local stack */
1125     if (!ic->parmPush) {
1126         /* and the item is spilt then do nothing */
1127         if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1128             return ;
1129
1130         aopOp(IC_LEFT(ic),ic,FALSE);
1131         size = AOP_SIZE(IC_LEFT(ic));
1132         /* push it on the stack */
1133         if (isPair(AOP(IC_LEFT(ic)))) {
1134             emitcode("push", getPairName(AOP(IC_LEFT(ic))));
1135             _pushed += 2;
1136         }
1137         else {
1138             offset = size;
1139             while (size--) {
1140                 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1141                 /* Simple for now - load into A and PUSH AF */
1142                 emitcode("ld", "a,%s", l);
1143                 emitcode("push", "af");
1144                 emitcode("inc", "sp");
1145                 _pushed++;
1146             }
1147         }
1148         return ;        
1149     }
1150
1151     /* Hmmm... what about saving the currently used registers
1152        at this point? */
1153
1154     /* then do the push */
1155     aopOp(IC_LEFT(ic),ic,FALSE);
1156
1157     size = AOP_SIZE(IC_LEFT(ic));
1158
1159     if (isPair(AOP(IC_LEFT(ic)))) {
1160         _pushed+=2;
1161         emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
1162     }
1163     else {
1164         if (size == 2) {
1165             char *s = aopGetWord(AOP(IC_LEFT(ic)), 0);
1166             if (s) {
1167                 emitcode("ld", "hl,%s", s);
1168                 emitcode("push", "hl");
1169                 _pushed+=2;
1170             }
1171             else {
1172                 /* Optimise here - load into HL then push HL */
1173                 fetchHL(AOP(IC_LEFT(ic)));
1174                 emitcode("push", "hl");
1175                 _pushed += 2;
1176             }
1177             goto release;
1178         }
1179         offset = size;
1180         while (size--) {
1181             l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
1182             emitcode("ld", "a,%s", l);
1183             emitcode("push", "af");
1184             emitcode("inc", "sp");
1185             _pushed++;
1186         }       
1187     }
1188  release:
1189     freeAsmop(IC_LEFT(ic),NULL,ic);
1190 }
1191
1192 /*-----------------------------------------------------------------*/
1193 /* genIpop - recover the registers: can happen only for spilling   */
1194 /*-----------------------------------------------------------------*/
1195 static void genIpop (iCode *ic)
1196 {
1197     int size,offset ;
1198
1199
1200     /* if the temp was not pushed then */
1201     if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1202         return ;
1203
1204     aopOp(IC_LEFT(ic),ic,FALSE);
1205     size = AOP_SIZE(IC_LEFT(ic));
1206     offset = (size-1);
1207     if (isPair(AOP(IC_LEFT(ic)))) {
1208         emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1209     }
1210     else {
1211         while (size--) {
1212             emitcode("dec", "sp");
1213             emitcode("pop", "hl");
1214             aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1215         }
1216     }
1217
1218     freeAsmop(IC_LEFT(ic),NULL,ic);
1219 }
1220
1221 /** Emit the code for a call statement 
1222  */
1223 static void emitCall (iCode *ic, bool ispcall)
1224 {
1225     /* if caller saves & we have not saved then */
1226     if (!ic->regsSaved) {
1227         /* PENDING */
1228     }
1229
1230     /* if send set is not empty then assign */
1231     if (sendSet) {
1232         iCode *sic ;
1233         for (sic = setFirstItem(sendSet) ; sic ; 
1234              sic = setNextItem(sendSet)) {
1235             int size, offset = 0;
1236             aopOp(IC_LEFT(sic),sic,FALSE);
1237             size = AOP_SIZE(IC_LEFT(sic));
1238             while (size--) {
1239                 char *l = aopGet(AOP(IC_LEFT(sic)),offset,
1240                                 FALSE);
1241                 if (strcmp(l, _fReturn[offset]))
1242                     emitcode("ld","%s,%s",
1243                              _fReturn[offset],
1244                              l);
1245                 offset++;
1246             }
1247             freeAsmop (IC_LEFT(sic),NULL,sic);
1248         }
1249         sendSet = NULL;
1250     }
1251
1252     if (ispcall) {
1253         symbol *rlbl = newiTempLabel(NULL);
1254
1255         emitcode("ld", "hl,#" LABEL_STR, (rlbl->key+100));
1256         emitcode("push", "hl");
1257         _pushed += 2;
1258
1259         aopOp(IC_LEFT(ic),ic,FALSE);
1260         fetchHL(AOP(IC_LEFT(ic)));
1261         freeAsmop(IC_LEFT(ic),NULL,ic); 
1262         
1263         emitcode("jp", "(hl)");
1264         emitcode("","%05d$:",(rlbl->key+100));
1265         _pushed -= 2;
1266     }
1267     else {
1268         /* make the call */
1269         char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1270             OP_SYMBOL(IC_LEFT(ic))->rname :
1271             OP_SYMBOL(IC_LEFT(ic))->name;
1272         emitcode("call", "%s", name);
1273     }
1274
1275     /* if we need assign a result value */
1276     if ((IS_ITEMP(IC_RESULT(ic)) && 
1277          (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1278           OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1279         IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1280
1281         accInUse++;
1282         aopOp(IC_RESULT(ic),ic,FALSE);
1283         accInUse--;
1284
1285         assignResultValue(IC_RESULT(ic));
1286                 
1287         freeAsmop(IC_RESULT(ic),NULL, ic);
1288     }
1289
1290     /* adjust the stack for parameters if required */
1291     if (IC_LEFT(ic)->parmBytes) {
1292         int i = IC_LEFT(ic)->parmBytes;
1293         _pushed -= i;
1294         if (IS_GB) {
1295             emitcode("lda", "sp,%d(sp)", i);
1296         }
1297         else {
1298             if (i>6) {
1299                 emitcode("ld", "hl,#%d", i);
1300                 emitcode("add", "hl,sp");
1301                 emitcode("ld", "sp,hl");
1302             }
1303             else {
1304                 while (i>1) {
1305                     emitcode("pop", "hl");
1306                     i-=2;
1307                 }
1308                 if (i) 
1309                     emitcode("inc", "sp");
1310             }
1311         }
1312     }
1313
1314 }
1315
1316 /*-----------------------------------------------------------------*/
1317 /* genCall - generates a call statement                            */
1318 /*-----------------------------------------------------------------*/
1319 static void genCall (iCode *ic)
1320 {
1321     emitCall(ic, FALSE);
1322 }
1323
1324 /*-----------------------------------------------------------------*/
1325 /* genPcall - generates a call by pointer statement                */
1326 /*-----------------------------------------------------------------*/
1327 static void genPcall (iCode *ic)
1328 {
1329     emitCall(ic, TRUE);
1330 }
1331
1332 /*-----------------------------------------------------------------*/
1333 /* resultRemat - result  is rematerializable                       */
1334 /*-----------------------------------------------------------------*/
1335 static int resultRemat (iCode *ic)
1336 {
1337     if (SKIP_IC(ic) || ic->op == IFX)
1338         return 0;
1339
1340     if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1341         symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1342         if (sym->remat && !POINTER_SET(ic)) 
1343             return 1;
1344     }
1345
1346     return 0;
1347 }
1348
1349 /*-----------------------------------------------------------------*/
1350 /* genFunction - generated code for function entry                 */
1351 /*-----------------------------------------------------------------*/
1352 static void genFunction (iCode *ic)
1353 {
1354     symbol *sym;
1355     link *fetype;
1356
1357     nregssaved = 0;
1358     /* create the function header */
1359     emitcode(";","-----------------------------------------");
1360     emitcode(";"," function %s",(sym = OP_SYMBOL(IC_LEFT(ic)))->name);
1361     emitcode(";","-----------------------------------------");
1362
1363     emitcode("","%s:",sym->rname);
1364     fetype = getSpec(operandType(IC_LEFT(ic)));
1365
1366     /* if critical function then turn interrupts off */
1367     if (SPEC_CRTCL(fetype))
1368         emitcode("di","");
1369
1370     /* if this is an interrupt service routine then
1371     save acc, b, dpl, dph  */
1372     if (IS_ISR(sym->etype)) {
1373         emitcode("push", "af");
1374         emitcode("push", "bc");
1375         emitcode("push", "de");
1376         emitcode("push", "hl");
1377     }
1378     /* PENDING: callee-save etc */
1379
1380     /* adjust the stack for the function */
1381     emitcode("push", "bc");
1382     if (!IS_GB) {
1383         emitcode("push", "de");
1384         emitcode("push", "ix");
1385         emitcode("ld", "ix,#0");
1386         emitcode("add", "ix,sp");
1387     }
1388
1389     _lastStack = sym->stack;
1390
1391     if (sym->stack) {
1392         if (IS_GB) {
1393             emitcode("lda", "sp,-%d(sp)", sym->stack);
1394         }
1395         else {
1396             emitcode("ld", "hl,#-%d", sym->stack);
1397             emitcode("add", "hl,sp");
1398             emitcode("ld", "sp,hl");
1399         }
1400     }
1401     _spoffset = sym->stack;
1402 }
1403
1404 /*-----------------------------------------------------------------*/
1405 /* genEndFunction - generates epilogue for functions               */
1406 /*-----------------------------------------------------------------*/
1407 static void genEndFunction (iCode *ic)
1408 {
1409     symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1410
1411     if (IS_ISR(sym->etype)) {
1412         assert(0);
1413     }
1414     else {
1415         if (SPEC_CRTCL(sym->etype))
1416             emitcode("ei", "");
1417         
1418         /* PENDING: calleeSave */
1419
1420         /* if debug then send end of function */
1421         if (options.debug && currFunc) { 
1422             debugLine = 1;
1423             emitcode("","C$%s$%d$%d$%d ==.",
1424                      ic->filename,currFunc->lastLine,
1425                      ic->level,ic->block); 
1426             if (IS_STATIC(currFunc->etype))         
1427                 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name); 
1428             else
1429                 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1430             debugLine = 0;
1431         }
1432         if (!IS_GB) {
1433             emitcode("ld", "sp,ix");
1434             emitcode("pop", "ix");
1435             emitcode("pop", "de");
1436         }
1437         else {
1438             if (_spoffset) {
1439                 emitcode("ld", "hl,#%d", _spoffset);
1440                 emitcode("add", "hl,sp");
1441                 emitcode("ld", "sp,hl");
1442             }
1443         }
1444         emitcode("pop", "bc");
1445         emitcode("ret", "");
1446     }
1447     _pushed = 0;
1448     _spoffset = 0;
1449 }
1450
1451 /*-----------------------------------------------------------------*/
1452 /* genRet - generate code for return statement                     */
1453 /*-----------------------------------------------------------------*/
1454 static void genRet (iCode *ic)
1455 {
1456     char *l;
1457     /* Errk.  This is a hack until I can figure out how
1458        to cause dehl to spill on a call */
1459     int size,offset = 0;
1460     
1461     /* if we have no return value then
1462        just generate the "ret" */
1463     if (!IC_LEFT(ic)) 
1464         goto jumpret;       
1465     
1466     /* we have something to return then
1467        move the return value into place */
1468     aopOp(IC_LEFT(ic),ic,FALSE);
1469     size = AOP_SIZE(IC_LEFT(ic));
1470     
1471     if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1472         if (IS_GB) {
1473             emitcode("ld", "de,%s", l);
1474         }
1475         else {
1476             emitcode("ld", "hl,%s", l);
1477         }
1478     }
1479     else {
1480         while (size--) {
1481             l = aopGet(AOP(IC_LEFT(ic)),offset,
1482                        FALSE);
1483             if (strcmp(_fReturn[offset],l))
1484                 emitcode("ld","%s,%s", _fReturn[offset++],l);
1485         }
1486     }
1487     freeAsmop (IC_LEFT(ic),NULL,ic);
1488     
1489  jumpret:
1490         /* generate a jump to the return label
1491            if the next is not the return statement */
1492     if (!(ic->next && ic->next->op == LABEL &&
1493           IC_LABEL(ic->next) == returnLabel))
1494         
1495         emitcode("jp",  LABEL_STR ,(returnLabel->key+100));
1496 }
1497
1498 /*-----------------------------------------------------------------*/
1499 /* genLabel - generates a label                                    */
1500 /*-----------------------------------------------------------------*/
1501 static void genLabel (iCode *ic)
1502 {
1503     /* special case never generate */
1504     if (IC_LABEL(ic) == entryLabel)
1505         return ;
1506
1507     emitcode("", LABEL_STR ":",(IC_LABEL(ic)->key+100));
1508 }
1509
1510 /*-----------------------------------------------------------------*/
1511 /* genGoto - generates a ljmp                                      */
1512 /*-----------------------------------------------------------------*/
1513 static void genGoto (iCode *ic)
1514 {
1515     emitcode ("jp", LABEL_STR ,(IC_LABEL(ic)->key+100));
1516 }
1517
1518 /*-----------------------------------------------------------------*/
1519 /* genPlusIncr :- does addition with increment if possible         */
1520 /*-----------------------------------------------------------------*/
1521 static bool genPlusIncr (iCode *ic)
1522 {
1523     unsigned int icount ;
1524     unsigned int size = getDataSize(IC_RESULT(ic));
1525     
1526     /* will try to generate an increment */
1527     /* if the right side is not a literal 
1528        we cannot */
1529     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1530         return FALSE;
1531     
1532     emitcode("", "; genPlusIncr");
1533
1534     icount = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1535
1536     /* If result is a pair */
1537     if (isPair(AOP(IC_RESULT(ic)))) {
1538         char *left = aopGetWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
1539         if (left) {
1540             /* Both a lit on the right and a true symbol on the left */
1541             emitcode("ld", "%s,#%s + %d", getPairName(AOP(IC_RESULT(ic))), left, icount);
1542             return TRUE;
1543         }
1544     }
1545
1546     /* if the literal value of the right hand side
1547        is greater than 4 then it is not worth it */
1548     if (icount > 4)
1549         return FALSE ;
1550
1551     /* Inc a pair */
1552     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1553         isPair(AOP(IC_RESULT(ic)))) {
1554         while (icount--) {
1555             emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1556         }
1557         return TRUE;
1558     }
1559     /* if increment 16 bits in register */
1560     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1561         (size > 1) &&
1562         (icount == 1)) {
1563         symbol *tlbl = newiTempLabel(NULL);
1564         emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
1565         emitcode(_shortJP, "nz," LABEL_STR ,tlbl->key+100);
1566     
1567         emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
1568         if(size == 4) {
1569             assert(0);
1570         }
1571         emitcode("", LABEL_STR ":",tlbl->key+100);
1572         return TRUE;
1573     }
1574
1575     /* If result is a pair */
1576     if (isPair(AOP(IC_RESULT(ic)))) {
1577         movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1578         movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1579         while (icount--)
1580             emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1581         return TRUE;
1582     }
1583
1584     /* if the sizes are greater than 1 then we cannot */
1585     if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1586         AOP_SIZE(IC_LEFT(ic)) > 1   )
1587         return FALSE ;
1588     
1589     /* we can if the aops of the left & result match or
1590        if they are in registers and the registers are the
1591        same */
1592     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
1593         while (icount--)
1594             emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
1595         
1596         return TRUE ;
1597     }
1598     
1599     return FALSE ;
1600 }
1601
1602 /*-----------------------------------------------------------------*/
1603 /* outBitAcc - output a bit in acc                                 */
1604 /*-----------------------------------------------------------------*/
1605 void outBitAcc(operand *result)
1606 {
1607     symbol *tlbl = newiTempLabel(NULL);
1608     /* if the result is a bit */
1609     if (AOP_TYPE(result) == AOP_CRY){
1610         assert(0);
1611     }
1612     else {
1613         emitcode(_shortJP,"z," LABEL_STR ,tlbl->key+100);
1614         emitcode("ld","a,%s",one);
1615         emitcode("", LABEL_STR ":",tlbl->key+100);
1616         outAcc(result);
1617     }
1618 }
1619
1620 /*-----------------------------------------------------------------*/
1621 /* genPlus - generates code for addition                           */
1622 /*-----------------------------------------------------------------*/
1623 static void genPlus (iCode *ic)
1624 {
1625     int size, offset = 0;
1626
1627     /* special cases :- */
1628
1629     aopOp (IC_LEFT(ic),ic,FALSE);
1630     aopOp (IC_RIGHT(ic),ic,FALSE);
1631     aopOp (IC_RESULT(ic),ic,TRUE);
1632
1633     /* Swap the left and right operands if:
1634
1635        if literal, literal on the right or
1636        if left requires ACC or right is already
1637        in ACC */
1638
1639     if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
1640         (AOP_NEEDSACC(IC_LEFT(ic))) ||
1641         AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
1642         operand *t = IC_RIGHT(ic);
1643         IC_RIGHT(ic) = IC_LEFT(ic);
1644         IC_LEFT(ic) = t;
1645     }
1646
1647     /* if both left & right are in bit
1648     space */
1649     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1650         AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1651         /* Cant happen */
1652         assert(0);
1653     }
1654
1655     /* if left in bit space & right literal */
1656     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1657         AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1658         /* Can happen I guess */
1659         assert(0);
1660     }
1661
1662     /* if I can do an increment instead
1663     of add then GOOD for ME */
1664     if (genPlusIncr (ic) == TRUE)
1665         goto release;   
1666
1667     size = getDataSize(IC_RESULT(ic));
1668
1669     /* Special case when left and right are constant */
1670     if (isPair(AOP(IC_RESULT(ic)))) {
1671         char *left, *right;
1672         
1673         left = aopGetWordLong(AOP(IC_LEFT(ic)), 0, FALSE);
1674         right = aopGetWordLong(AOP(IC_RIGHT(ic)), 0, FALSE);
1675         if (left && right) {
1676             /* It's a pair */
1677             /* PENDING: fix */
1678             char buffer[100];
1679             sprintf(buffer, "#(%s + %s)", left, right);
1680             emitcode("ld", "%s,%s", getPairName(AOP(IC_RESULT(ic))), buffer);
1681             goto release;
1682         }
1683     }
1684
1685     while(size--) {
1686         if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
1687             MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1688             if(offset == 0)
1689                 emitcode("add","a,%s",
1690                          aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1691             else
1692                 emitcode("adc","a,%s",
1693                          aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1694         } else {
1695             MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1696             if(offset == 0)
1697                 emitcode("add","a,%s",
1698                          aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1699             else
1700                 emitcode("adc","a,%s",
1701                          aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1702         }
1703         aopPut(AOP(IC_RESULT(ic)),"a",offset++);      
1704     }
1705
1706     /* Some kind of pointer arith. */
1707     if (AOP_SIZE(IC_RESULT(ic)) == 3 && 
1708         AOP_SIZE(IC_LEFT(ic)) == 3   &&
1709         !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1710         assert(0);
1711
1712      if (AOP_SIZE(IC_RESULT(ic)) == 3 && 
1713         AOP_SIZE(IC_RIGHT(ic)) == 3   &&
1714         !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
1715          assert(0);
1716
1717    
1718 release:
1719     freeAsmop(IC_LEFT(ic),NULL,ic);
1720     freeAsmop(IC_RIGHT(ic),NULL,ic);
1721     freeAsmop(IC_RESULT(ic),NULL,ic);
1722     
1723 }
1724
1725 /*-----------------------------------------------------------------*/
1726 /* genMinusDec :- does subtraction with deccrement if possible     */
1727 /*-----------------------------------------------------------------*/
1728 static bool genMinusDec (iCode *ic)
1729 {
1730     unsigned int icount ;
1731     unsigned int size = getDataSize(IC_RESULT(ic));
1732
1733     /* will try to generate an increment */
1734     /* if the right side is not a literal we cannot */
1735     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1736         return FALSE ;
1737
1738     /* if the literal value of the right hand side
1739     is greater than 4 then it is not worth it */
1740     if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
1741         return FALSE;
1742
1743     size = getDataSize(IC_RESULT(ic));
1744
1745 #if 0
1746     /* if increment 16 bits in register */
1747     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1748         (size > 1) &&
1749         (icount == 1)) {
1750         symbol *tlbl = newiTempLabel(NULL);
1751         emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
1752         emitcode("jp", "np," LABEL_STR ,tlbl->key+100);
1753     
1754         emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
1755         if(size == 4) {
1756             assert(0);
1757         }
1758         emitcode("", LABEL_STR ":",tlbl->key+100);
1759         return TRUE;
1760     }
1761 #endif
1762
1763     /* if decrement 16 bits in register */
1764     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1765         (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
1766         while (icount--)
1767             emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
1768         return TRUE;
1769     }
1770
1771     /* If result is a pair */
1772     if (isPair(AOP(IC_RESULT(ic)))) {
1773         movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1774         movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1775         while (icount--)
1776             emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
1777         return TRUE;
1778     }
1779
1780     /* if the sizes are greater than 1 then we cannot */
1781     if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1782         AOP_SIZE(IC_LEFT(ic)) > 1   )
1783         return FALSE ;
1784
1785     /* we can if the aops of the left & result match or if they are in
1786        registers and the registers are the same */
1787     if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
1788         while (icount--) 
1789             emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
1790         return TRUE ;
1791     }
1792
1793     return FALSE ;
1794 }
1795
1796 /*-----------------------------------------------------------------*/
1797 /* genMinus - generates code for subtraction                       */
1798 /*-----------------------------------------------------------------*/
1799 static void genMinus (iCode *ic)
1800 {
1801     int size, offset = 0;
1802     unsigned long lit = 0L;
1803
1804     aopOp (IC_LEFT(ic),ic,FALSE);
1805     aopOp (IC_RIGHT(ic),ic,FALSE);
1806     aopOp (IC_RESULT(ic),ic,TRUE);
1807
1808     /* special cases :- */
1809     /* if both left & right are in bit space */
1810     if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1811         AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1812         assert(0);
1813         goto release ;
1814     }
1815
1816     /* if I can do an decrement instead of subtract then GOOD for ME */
1817     if (genMinusDec (ic) == TRUE)
1818         goto release;   
1819
1820     size = getDataSize(IC_RESULT(ic));   
1821
1822     if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
1823     }
1824     else{
1825         lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1826         lit = - (long)lit;
1827     }
1828
1829
1830     /* if literal, add a,#-lit, else normal subb */
1831     while (size--) {
1832         MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));    
1833         if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) {
1834             if (!offset)
1835                 emitcode("sub","a,%s",
1836                          aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1837             else
1838                 emitcode("sbc","a,%s",
1839                          aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1840         }
1841         else{
1842             /* first add without previous c */
1843             if (!offset)
1844                 emitcode("add","a,#0x%02x",
1845                          (unsigned int)(lit & 0x0FFL));
1846             else
1847                 emitcode("adc","a,#0x%02x",
1848                          (unsigned int)((lit >> (offset*8)) & 0x0FFL));
1849         }
1850         aopPut(AOP(IC_RESULT(ic)),"a",offset++);      
1851     }
1852     
1853     if (AOP_SIZE(IC_RESULT(ic)) == 3 && 
1854         AOP_SIZE(IC_LEFT(ic)) == 3   &&
1855         !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1856         assert(0);
1857
1858 release:
1859     freeAsmop(IC_LEFT(ic),NULL,ic);
1860     freeAsmop(IC_RIGHT(ic),NULL,ic);
1861     freeAsmop(IC_RESULT(ic),NULL,ic);
1862 }
1863
1864 /*-----------------------------------------------------------------*/
1865 /* genMult - generates code for multiplication                     */
1866 /*-----------------------------------------------------------------*/
1867 static void genMult (iCode *ic)
1868 {
1869     /* Shouldn't occur - all done through function calls */
1870     assert(0);
1871 }
1872
1873 /*-----------------------------------------------------------------*/
1874 /* genDiv - generates code for division                            */
1875 /*-----------------------------------------------------------------*/
1876 static void genDiv (iCode *ic)
1877 {
1878     /* Shouldn't occur - all done through function calls */
1879     assert(0);
1880 }
1881
1882 /*-----------------------------------------------------------------*/
1883 /* genMod - generates code for division                            */
1884 /*-----------------------------------------------------------------*/
1885 static void genMod (iCode *ic)
1886 {
1887     /* Shouldn't occur - all done through function calls */
1888     assert(0);
1889 }
1890
1891 /*-----------------------------------------------------------------*/
1892 /* genIfxJump :- will create a jump depending on the ifx           */
1893 /*-----------------------------------------------------------------*/
1894 static void genIfxJump (iCode *ic, char *jval)
1895 {
1896     symbol *jlbl ;
1897     const char *inst;
1898
1899     /* if true label then we jump if condition
1900     supplied is true */
1901     if ( IC_TRUE(ic) ) {
1902         jlbl = IC_TRUE(ic);
1903         if (!strcmp(jval, "a")) {
1904             inst = "nz";
1905         }
1906         else if (!strcmp(jval, "c")) {
1907             inst = "c";
1908         }
1909         else {
1910             /* The buffer contains the bit on A that we should test */
1911             inst = "nz";
1912         }
1913     }
1914     else {
1915         /* false label is present */
1916         jlbl = IC_FALSE(ic) ;
1917         if (!strcmp(jval, "a")) {
1918             inst = "z";
1919         }
1920         else if (!strcmp(jval, "c")) {
1921             inst = "nc";
1922         }
1923         else {
1924             /* The buffer contains the bit on A that we should test */
1925             inst = "z";
1926         }
1927     }
1928     /* Z80 can do a conditional long jump */
1929     if (!strcmp(jval, "a")) {
1930         emitcode("or", "a,a");
1931     }
1932     else if (!strcmp(jval, "c")) {
1933     }
1934     else {
1935         emitcode("bit", "%s,a", jval);
1936     }
1937     emitcode("jp", "%s," LABEL_STR , inst, jlbl->key+100);
1938
1939     /* mark the icode as generated */
1940     ic->generated = 1;
1941 }
1942
1943 /** Generic compare for > or <
1944  */
1945 static void genCmp (operand *left,operand *right,
1946                     operand *result, iCode *ifx, int sign)
1947 {
1948     int size, offset = 0 ;
1949     unsigned long lit = 0L;
1950
1951     /* if left & right are bit variables */
1952     if (AOP_TYPE(left) == AOP_CRY &&
1953         AOP_TYPE(right) == AOP_CRY ) {
1954         /* Cant happen on the Z80 */
1955         assert(0);
1956     } else {
1957         /* subtract right from left if at the
1958         end the carry flag is set then we know that
1959         left is greater than right */
1960         size = max(AOP_SIZE(left),AOP_SIZE(right));
1961
1962         /* if unsigned char cmp with lit, just compare */
1963         if((size == 1) && 
1964            (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
1965             emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
1966             if (sign) {
1967                 emitcode("xor", "a,#0x80");
1968                 emitcode("cp", "%s^0x80", aopGet(AOP(right), offset, FALSE));
1969             }
1970             else 
1971                 emitcode("cp", "%s ; 7", aopGet(AOP(right), offset, FALSE));
1972         } 
1973         else {
1974             if(AOP_TYPE(right) == AOP_LIT) {
1975                 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
1976                 /* optimize if(x < 0) or if(x >= 0) */
1977                 if (lit == 0L){
1978                     if (!sign) {
1979                         /* No sign so it's always false */
1980                         CLRC;
1981                     }
1982                     else{
1983                         /* Just load in the top most bit */
1984                         MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
1985                         if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
1986                             genIfxJump (ifx,"7");
1987                             return;
1988                         }
1989                         else    
1990                             emitcode("rlc","a");
1991                     }
1992                     goto release;
1993                 }
1994             }
1995             if (sign) {
1996                 /* First setup h and l contaning the top most bytes XORed */
1997                 bool fDidXor = FALSE;
1998                 if (AOP_TYPE(left) == AOP_LIT){
1999                     unsigned long lit = (unsigned long)
2000                         floatFromVal(AOP(left)->aopu.aop_lit);
2001                     emitcode("ld", "%s,#0x%02x", _fTmp[0],
2002                              0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2003                 }
2004                 else {
2005                     emitcode("ld", "a,%s", aopGet(AOP(left), size-1, FALSE));
2006                     emitcode("xor", "a,#0x80");
2007                     emitcode("ld", "%s,a", _fTmp[0]);
2008                     fDidXor = TRUE;
2009                 }
2010                 if (AOP_TYPE(right) == AOP_LIT) {
2011                     unsigned long lit = (unsigned long)
2012                         floatFromVal(AOP(right)->aopu.aop_lit);
2013                     emitcode("ld", "%s,#0x%02x", _fTmp[1],
2014                              0x80 ^ (unsigned int)((lit >> ((size-1)*8)) & 0x0FFL));
2015                 }
2016                 else {
2017                     emitcode("ld", "a,%s", aopGet(AOP(right), size-1, FALSE));
2018                     emitcode("xor", "a,#0x80");
2019                     emitcode("ld", "%s,a", _fTmp[1]);
2020                     fDidXor = TRUE;
2021                 }
2022                 if (!fDidXor)
2023                     CLRC;
2024             }
2025             else {
2026                 CLRC;
2027             }
2028             while (size--) {
2029                 /* Do a long subtract */
2030                 if (!sign || size) 
2031                     MOVA(aopGet(AOP(left),offset,FALSE));
2032                 if (sign && size == 0) {
2033                     emitcode("ld", "a,%s", _fTmp[0]);
2034                     emitcode("sbc", "a,%s", _fTmp[1]);
2035                 }
2036                 else {
2037                     /* Subtract through, propagating the carry */
2038                     emitcode("sbc","a,%s",aopGet(AOP(right),offset++,FALSE));
2039                 }
2040             }
2041         }
2042     }
2043
2044 release:
2045     if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2046         outBitC(result);
2047     } else {
2048         /* if the result is used in the next
2049         ifx conditional branch then generate
2050         code a little differently */
2051         if (ifx )
2052             genIfxJump (ifx,"c");
2053         else
2054             outBitC(result);
2055         /* leave the result in acc */
2056     }
2057 }
2058
2059 /*-----------------------------------------------------------------*/
2060 /* genCmpGt :- greater than comparison                             */
2061 /*-----------------------------------------------------------------*/
2062 static void genCmpGt (iCode *ic, iCode *ifx)
2063 {
2064     operand *left, *right, *result;
2065     link *letype , *retype;
2066     int sign ;
2067
2068     left = IC_LEFT(ic);
2069     right= IC_RIGHT(ic);
2070     result = IC_RESULT(ic);
2071
2072     letype = getSpec(operandType(left));
2073     retype =getSpec(operandType(right));
2074     sign =  !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2075     /* assign the amsops */
2076     aopOp (left,ic,FALSE);
2077     aopOp (right,ic,FALSE);
2078     aopOp (result,ic,TRUE);
2079
2080     genCmp(right, left, result, ifx, sign);
2081
2082     freeAsmop(left,NULL,ic);
2083     freeAsmop(right,NULL,ic);
2084     freeAsmop(result,NULL,ic);
2085 }
2086
2087 /*-----------------------------------------------------------------*/
2088 /* genCmpLt - less than comparisons                                */
2089 /*-----------------------------------------------------------------*/
2090 static void genCmpLt (iCode *ic, iCode *ifx)
2091 {
2092     operand *left, *right, *result;
2093     link *letype , *retype;
2094     int sign ;
2095
2096     left = IC_LEFT(ic);
2097     right= IC_RIGHT(ic);
2098     result = IC_RESULT(ic);
2099
2100     letype = getSpec(operandType(left));
2101     retype =getSpec(operandType(right));
2102     sign =  !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
2103
2104     /* assign the amsops */
2105     aopOp (left,ic,FALSE);
2106     aopOp (right,ic,FALSE);
2107     aopOp (result,ic,TRUE);
2108
2109     genCmp(left, right, result, ifx, sign);
2110
2111     freeAsmop(left,NULL,ic);
2112     freeAsmop(right,NULL,ic);
2113     freeAsmop(result,NULL,ic);
2114 }
2115
2116 /*-----------------------------------------------------------------*/
2117 /* gencjneshort - compare and jump if not equal                    */
2118 /*-----------------------------------------------------------------*/
2119 static void gencjneshort(operand *left, operand *right, symbol *lbl)
2120 {
2121     int size = max(AOP_SIZE(left),AOP_SIZE(right));
2122     int offset = 0;
2123     unsigned long lit = 0L;
2124
2125     /* Swap the left and right if it makes the computation easier */
2126     if (AOP_TYPE(left) == AOP_LIT) {
2127         operand *t = right;
2128         right = left;
2129         left = t;
2130     }
2131
2132     if(AOP_TYPE(right) == AOP_LIT)
2133         lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
2134
2135     /* if the right side is a literal then anything goes */
2136     if (AOP_TYPE(right) == AOP_LIT &&
2137         AOP_TYPE(left) != AOP_DIR ) {
2138         while (size--) {
2139             emitcode("ld", "a,%s ; 2", aopGet(AOP(left),offset,FALSE));
2140             if ((AOP_TYPE(right) == AOP_LIT) && lit == 0)
2141                 emitcode("or", "a,a");
2142             else 
2143                 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
2144             emitcode("jp", "nz," LABEL_STR , lbl->key+100);
2145             offset++;
2146         }
2147     }
2148     /* if the right side is in a register or in direct space or
2149     if the left is a pointer register & right is not */    
2150     else if (AOP_TYPE(right) == AOP_REG ||
2151              AOP_TYPE(right) == AOP_DIR || 
2152              (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
2153         while (size--) {
2154             MOVA(aopGet(AOP(left),offset,FALSE));
2155             if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
2156                ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
2157                 /* PENDING */
2158                 emitcode("jp","nz," LABEL_STR ,lbl->key+100);
2159             else {
2160                 emitcode("cp", "%s ; 4", aopGet(AOP(right),offset,FALSE));
2161                 emitcode("jp", "nz," LABEL_STR , lbl->key+100);
2162             }
2163             offset++;
2164         }
2165     } else {
2166         /* right is a pointer reg need both a & b */
2167         /* PENDING: is this required? */
2168         while(size--) {
2169             char *l = aopGet(AOP(left),offset,FALSE);
2170             MOVA(aopGet(AOP(right),offset,FALSE));
2171             emitcode("cp", "%s ; 5", l);
2172             emitcode("jr", "nz," LABEL_STR, lbl->key+100);
2173             offset++;
2174         }
2175     }
2176 }
2177
2178 /*-----------------------------------------------------------------*/
2179 /* gencjne - compare and jump if not equal                         */
2180 /*-----------------------------------------------------------------*/
2181 static void gencjne(operand *left, operand *right, symbol *lbl)
2182 {
2183     symbol *tlbl  = newiTempLabel(NULL);
2184
2185     gencjneshort(left, right, lbl);
2186
2187     /* PENDING: ?? */
2188     emitcode("ld","a,%s",one);
2189     emitcode(_shortJP, LABEL_STR ,tlbl->key+100);
2190     emitcode("", LABEL_STR ":",lbl->key+100);
2191     emitcode("xor","a,a");
2192     emitcode("", LABEL_STR ":",tlbl->key+100);
2193 }
2194
2195 /*-----------------------------------------------------------------*/
2196 /* genCmpEq - generates code for equal to                          */
2197 /*-----------------------------------------------------------------*/
2198 static void genCmpEq (iCode *ic, iCode *ifx)
2199 {
2200     operand *left, *right, *result;
2201
2202     aopOp((left=IC_LEFT(ic)),ic,FALSE);
2203     aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2204     aopOp((result=IC_RESULT(ic)),ic,TRUE);
2205
2206     /* Swap operands if it makes the operation easier. ie if:
2207        1.  Left is a literal.
2208     */
2209     if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
2210         operand *t = IC_RIGHT(ic);
2211         IC_RIGHT(ic) = IC_LEFT(ic);
2212         IC_LEFT(ic) = t;
2213     }
2214
2215     if (ifx && !AOP_SIZE(result)){
2216         symbol *tlbl;
2217         /* if they are both bit variables */
2218         if (AOP_TYPE(left) == AOP_CRY &&
2219             ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2220             assert(0);
2221         } else {
2222             tlbl = newiTempLabel(NULL);
2223             gencjneshort(left, right, tlbl);
2224             if ( IC_TRUE(ifx) ) {
2225                 emitcode("jp", LABEL_STR ,IC_TRUE(ifx)->key+100);
2226                 emitcode("", LABEL_STR ":",tlbl->key+100);                
2227             } else {
2228                 /* PENDING: do this better */
2229                 symbol *lbl = newiTempLabel(NULL);
2230                 emitcode(_shortJP, LABEL_STR ,lbl->key+100);
2231                 emitcode("", LABEL_STR ":",tlbl->key+100);                
2232                 emitcode("jp", LABEL_STR ,IC_FALSE(ifx)->key+100);
2233                 emitcode("", LABEL_STR ":",lbl->key+100);             
2234             }
2235         }
2236         /* mark the icode as generated */
2237         ifx->generated = 1;
2238         goto release ;
2239     }
2240
2241     /* if they are both bit variables */
2242     if (AOP_TYPE(left) == AOP_CRY &&
2243         ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
2244         assert(0);
2245     } else {
2246         gencjne(left,right,newiTempLabel(NULL));    
2247         if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
2248             assert(0);
2249         }
2250         if (ifx) {
2251             genIfxJump(ifx,"a");
2252             goto release;
2253         }
2254         /* if the result is used in an arithmetic operation
2255         then put the result in place */
2256         if (AOP_TYPE(result) != AOP_CRY) {
2257             outAcc(result);
2258         }
2259         /* leave the result in acc */
2260     }
2261
2262 release:
2263     freeAsmop(left,NULL,ic);
2264     freeAsmop(right,NULL,ic);
2265     freeAsmop(result,NULL,ic);
2266 }
2267
2268 /*-----------------------------------------------------------------*/
2269 /* ifxForOp - returns the icode containing the ifx for operand     */
2270 /*-----------------------------------------------------------------*/
2271 static iCode *ifxForOp ( operand *op, iCode *ic )
2272 {
2273     /* if true symbol then needs to be assigned */
2274     if (IS_TRUE_SYMOP(op))
2275         return NULL ;
2276
2277     /* if this has register type condition and
2278     the next instruction is ifx with the same operand
2279     and live to of the operand is upto the ifx only then */
2280     if (ic->next &&
2281         ic->next->op == IFX &&
2282         IC_COND(ic->next)->key == op->key &&
2283         OP_SYMBOL(op)->liveTo <= ic->next->seq )
2284         return ic->next;
2285
2286     return NULL;
2287 }
2288
2289 /*-----------------------------------------------------------------*/
2290 /* genAndOp - for && operation                                     */
2291 /*-----------------------------------------------------------------*/
2292 static void genAndOp (iCode *ic)
2293 {
2294     operand *left,*right, *result;
2295     symbol *tlbl;
2296
2297     /* note here that && operations that are in an if statement are
2298        taken away by backPatchLabels only those used in arthmetic
2299        operations remain */
2300     aopOp((left=IC_LEFT(ic)),ic,FALSE);
2301     aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2302     aopOp((result=IC_RESULT(ic)),ic,FALSE);
2303
2304     /* if both are bit variables */
2305     if (AOP_TYPE(left) == AOP_CRY &&
2306         AOP_TYPE(right) == AOP_CRY ) {
2307         assert(0);
2308     } else {
2309         tlbl = newiTempLabel(NULL);
2310         toBoolean(left);    
2311         emitcode(_shortJP, "z," LABEL_STR ,tlbl->key+100);
2312         toBoolean(right);
2313         emitcode("", LABEL_STR ":",tlbl->key+100);
2314         outBitAcc(result);
2315     }
2316
2317     freeAsmop(left,NULL,ic);
2318     freeAsmop(right,NULL,ic);
2319     freeAsmop(result,NULL,ic);
2320 }
2321
2322 /*-----------------------------------------------------------------*/
2323 /* genOrOp - for || operation                                      */
2324 /*-----------------------------------------------------------------*/
2325 static void genOrOp (iCode *ic)
2326 {
2327     operand *left,*right, *result;
2328     symbol *tlbl;
2329
2330     /* note here that || operations that are in an
2331        if statement are taken away by backPatchLabels
2332        only those used in arthmetic operations remain */
2333     aopOp((left=IC_LEFT(ic)),ic,FALSE);
2334     aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2335     aopOp((result=IC_RESULT(ic)),ic,FALSE);
2336
2337     /* if both are bit variables */
2338     if (AOP_TYPE(left) == AOP_CRY &&
2339         AOP_TYPE(right) == AOP_CRY ) {
2340         assert(0);
2341     } else {
2342         tlbl = newiTempLabel(NULL);
2343         toBoolean(left);
2344         emitcode(_shortJP, "nz," LABEL_STR,tlbl->key+100);
2345         toBoolean(right);
2346         emitcode("", LABEL_STR,tlbl->key+100);
2347         outBitAcc(result);
2348     }
2349
2350     freeAsmop(left,NULL,ic);
2351     freeAsmop(right,NULL,ic);
2352     freeAsmop(result,NULL,ic);
2353 }
2354
2355 /*-----------------------------------------------------------------*/
2356 /* isLiteralBit - test if lit == 2^n                               */
2357 /*-----------------------------------------------------------------*/
2358 int isLiteralBit(unsigned long lit)
2359 {
2360     unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2361     0x100L,0x200L,0x400L,0x800L,
2362     0x1000L,0x2000L,0x4000L,0x8000L,
2363     0x10000L,0x20000L,0x40000L,0x80000L,
2364     0x100000L,0x200000L,0x400000L,0x800000L,
2365     0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2366     0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2367     int idx;
2368     
2369     for(idx = 0; idx < 32; idx++)
2370         if(lit == pw[idx])
2371             return idx+1;
2372     return 0;
2373 }
2374
2375 /*-----------------------------------------------------------------*/
2376 /* genAnd  - code for and                                          */
2377 /*-----------------------------------------------------------------*/
2378 static void genAnd (iCode *ic, iCode *ifx)
2379 {
2380     operand *left, *right, *result;
2381     int size, offset=0;  
2382     unsigned long lit = 0L;
2383     int bytelit = 0;
2384
2385     aopOp((left = IC_LEFT(ic)),ic,FALSE);
2386     aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2387     aopOp((result=IC_RESULT(ic)),ic,TRUE);
2388
2389 #ifdef DEBUG_TYPE
2390     emitcode("","; Type res[%d] = l[%d]&r[%d]",
2391              AOP_TYPE(result),
2392              AOP_TYPE(left), AOP_TYPE(right));
2393     emitcode("","; Size res[%d] = l[%d]&r[%d]",
2394              AOP_SIZE(result),
2395              AOP_SIZE(left), AOP_SIZE(right));
2396 #endif
2397
2398     /* if left is a literal & right is not then exchange them */
2399     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2400         AOP_NEEDSACC(left)) {
2401         operand *tmp = right ;
2402         right = left;
2403         left = tmp;
2404     }
2405
2406     /* if result = right then exchange them */
2407     if(sameRegs(AOP(result),AOP(right))){
2408         operand *tmp = right ;
2409         right = left;
2410         left = tmp;
2411     }
2412
2413     /* if right is bit then exchange them */
2414     if (AOP_TYPE(right) == AOP_CRY &&
2415         AOP_TYPE(left) != AOP_CRY){
2416         operand *tmp = right ;
2417         right = left;
2418         left = tmp;
2419     }
2420     if(AOP_TYPE(right) == AOP_LIT)
2421         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2422
2423     size = AOP_SIZE(result);
2424
2425     if (AOP_TYPE(left) == AOP_CRY){
2426         assert(0);
2427         goto release ;
2428     }
2429
2430     // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
2431     // bit = val & 0xZZ     - size = 1, ifx = FALSE -
2432     if((AOP_TYPE(right) == AOP_LIT) &&
2433        (AOP_TYPE(result) == AOP_CRY) &&
2434        (AOP_TYPE(left) != AOP_CRY)) {
2435         int posbit = isLiteralBit(lit);
2436         /* left &  2^n */
2437         if(posbit){
2438             posbit--;
2439             MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2440             // bit = left & 2^n
2441             if(size) {
2442                 assert(0);
2443                 emitcode("mov","c,acc.%d",posbit&0x07);
2444             }
2445             // if(left &  2^n)
2446             else{
2447                 if (ifx) {
2448                     sprintf(buffer, "%d", posbit&0x07);
2449                     genIfxJump(ifx, buffer);
2450                 }
2451                 else {
2452                     assert(0);
2453                 }
2454                 goto release;
2455             }
2456         } else {
2457             symbol *tlbl = newiTempLabel(NULL);
2458             int sizel = AOP_SIZE(left);
2459             if(size) {
2460                 assert(0);
2461                 emitcode("setb","c");
2462             }
2463             while(sizel--){
2464                 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2465                     MOVA( aopGet(AOP(left),offset,FALSE));
2466                     // byte ==  2^n ?
2467                     if((posbit = isLiteralBit(bytelit)) != 0) {
2468                         assert(0);
2469                         emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2470                     }
2471                     else{
2472                         if(bytelit != 0x0FFL)
2473                             emitcode("and","a,%s",
2474                                      aopGet(AOP(right),offset,FALSE));
2475                         emitcode("jr","nz, %05d$",tlbl->key+100);
2476                     }
2477                 }
2478                 offset++;
2479             }
2480             // bit = left & literal
2481             if (size){
2482                 emitcode("clr","c");
2483                 emitcode("","%05d$:",tlbl->key+100);
2484             }
2485             // if(left & literal)
2486             else{
2487                 if(ifx)
2488 #if 0
2489                     jmpTrueOrFalse(ifx, tlbl);
2490 #else
2491                 assert(0);
2492 #endif
2493                 goto release ;
2494             }
2495         }
2496         outBitC(result);
2497         goto release ;
2498     }
2499
2500     /* if left is same as result */
2501     if(sameRegs(AOP(result),AOP(left))){
2502         for(;size--; offset++) {
2503             if(AOP_TYPE(right) == AOP_LIT){
2504                 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2505                     continue;
2506                 else {
2507                     if (bytelit == 0)
2508                         aopPut(AOP(result),zero,offset);
2509                     else {
2510                         MOVA(aopGet(AOP(left),offset,FALSE));
2511                         emitcode("and","a,%s",
2512                                  aopGet(AOP(right),offset,FALSE));
2513                         emitcode("ld", "%s,a", aopGet(AOP(left),offset,FALSE));
2514                     }
2515                 }
2516
2517             } else {
2518                 if (AOP_TYPE(left) == AOP_ACC) {
2519                     assert(0);
2520                 }
2521                 else {
2522                     MOVA(aopGet(AOP(right),offset,FALSE));
2523                     emitcode("and","%s,a",
2524                              aopGet(AOP(left),offset,FALSE));
2525                 }
2526             }
2527         }
2528     } else {
2529         // left & result in different registers
2530         if(AOP_TYPE(result) == AOP_CRY){
2531             assert(0);
2532         } else {
2533             for(;(size--);offset++) {
2534                 // normal case
2535                 // result = left & right
2536                 if(AOP_TYPE(right) == AOP_LIT){
2537                     if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
2538                         aopPut(AOP(result),
2539                                aopGet(AOP(left),offset,FALSE),
2540                                offset);
2541                         continue;
2542                     } else if(bytelit == 0){
2543                         aopPut(AOP(result),zero,offset);
2544                         continue;
2545                     }
2546                 }
2547                 // faster than result <- left, anl result,right
2548                 // and better if result is SFR
2549                 if (AOP_TYPE(left) == AOP_ACC) 
2550                     emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
2551                 else {
2552                     MOVA(aopGet(AOP(right),offset,FALSE));
2553                     emitcode("and","a,%s",
2554                              aopGet(AOP(left),offset,FALSE));
2555                 }
2556                 aopPut(AOP(result),"a",offset);
2557             }
2558         }
2559
2560     }
2561
2562 release :
2563     freeAsmop(left,NULL,ic);
2564     freeAsmop(right,NULL,ic);
2565     freeAsmop(result,NULL,ic);
2566 }
2567
2568 /*-----------------------------------------------------------------*/
2569 /* genOr  - code for or                                            */
2570 /*-----------------------------------------------------------------*/
2571 static void genOr (iCode *ic, iCode *ifx)
2572 {
2573     operand *left, *right, *result;
2574     int size, offset=0;
2575     unsigned long lit = 0L;
2576
2577     aopOp((left = IC_LEFT(ic)),ic,FALSE);
2578     aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2579     aopOp((result=IC_RESULT(ic)),ic,TRUE);
2580
2581 #if 1
2582     emitcode("","; Type res[%d] = l[%d]&r[%d]",
2583              AOP_TYPE(result),
2584              AOP_TYPE(left), AOP_TYPE(right));
2585     emitcode("","; Size res[%d] = l[%d]&r[%d]",
2586              AOP_SIZE(result),
2587              AOP_SIZE(left), AOP_SIZE(right));
2588 #endif
2589
2590     /* if left is a literal & right is not then exchange them */
2591     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2592         AOP_NEEDSACC(left)) {
2593         operand *tmp = right ;
2594         right = left;
2595         left = tmp;
2596     }
2597
2598     /* if result = right then exchange them */
2599     if(sameRegs(AOP(result),AOP(right))){
2600         operand *tmp = right ;
2601         right = left;
2602         left = tmp;
2603     }
2604
2605     /* if right is bit then exchange them */
2606     if (AOP_TYPE(right) == AOP_CRY &&
2607         AOP_TYPE(left) != AOP_CRY){
2608         operand *tmp = right ;
2609         right = left;
2610         left = tmp;
2611     }
2612     if(AOP_TYPE(right) == AOP_LIT)
2613         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2614
2615     size = AOP_SIZE(result);
2616
2617     if (AOP_TYPE(left) == AOP_CRY){
2618         assert(0);
2619         goto release ;
2620     }
2621
2622     if((AOP_TYPE(right) == AOP_LIT) &&
2623        (AOP_TYPE(result) == AOP_CRY) &&
2624        (AOP_TYPE(left) != AOP_CRY)){
2625         assert(0);
2626         goto release ;
2627     }
2628
2629     /* if left is same as result */
2630     if(sameRegs(AOP(result),AOP(left))){
2631         for(;size--; offset++) {
2632             if(AOP_TYPE(right) == AOP_LIT){
2633                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2634                     continue;
2635                 else 
2636                     emitcode("or","%s,%s; 5",
2637                              aopGet(AOP(left),offset,FALSE),
2638                              aopGet(AOP(right),offset,FALSE));
2639             } else {
2640                 if (AOP_TYPE(left) == AOP_ACC) 
2641                     emitcode("or","a,%s ; 6",aopGet(AOP(right),offset,FALSE));
2642                 else {              
2643                     MOVA(aopGet(AOP(right),offset,FALSE));
2644                     emitcode("or","a,%s ; 7",
2645                              aopGet(AOP(left),offset,FALSE));
2646                     aopPut(AOP(result),"a ; 8", offset);
2647                 }
2648             }
2649         }
2650     } else {
2651         // left & result in different registers
2652         if(AOP_TYPE(result) == AOP_CRY){
2653             assert(0);
2654         } else for(;(size--);offset++){
2655             // normal case
2656             // result = left & right
2657             if(AOP_TYPE(right) == AOP_LIT){
2658                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2659                     aopPut(AOP(result),
2660                            aopGet(AOP(left),offset,FALSE),
2661                            offset);
2662                     continue;
2663                 }
2664             }
2665             // faster than result <- left, anl result,right
2666             // and better if result is SFR
2667             if (AOP_TYPE(left) == AOP_ACC) 
2668                 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2669             else {
2670                 MOVA(aopGet(AOP(right),offset,FALSE));
2671                 emitcode("or","a,%s",
2672                          aopGet(AOP(left),offset,FALSE));
2673             }
2674             aopPut(AOP(result),"a",offset);                     
2675             /* PENDING: something weird is going on here.  Add exception. */
2676             if (AOP_TYPE(result) == AOP_ACC)
2677                 break;
2678         }
2679     }
2680
2681 release :
2682     freeAsmop(left,NULL,ic);
2683     freeAsmop(right,NULL,ic);
2684     freeAsmop(result,NULL,ic);
2685 }
2686
2687 /*-----------------------------------------------------------------*/
2688 /* genXor - code for xclusive or                                   */
2689 /*-----------------------------------------------------------------*/
2690 static void genXor (iCode *ic, iCode *ifx)
2691 {
2692     operand *left, *right, *result;
2693     int size, offset=0;
2694     unsigned long lit = 0L;
2695
2696     aopOp((left = IC_LEFT(ic)),ic,FALSE);
2697     aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2698     aopOp((result=IC_RESULT(ic)),ic,TRUE);
2699
2700     /* if left is a literal & right is not then exchange them */
2701     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2702         AOP_NEEDSACC(left)) {
2703         operand *tmp = right ;
2704         right = left;
2705         left = tmp;
2706     }
2707
2708     /* if result = right then exchange them */
2709     if(sameRegs(AOP(result),AOP(right))){
2710         operand *tmp = right ;
2711         right = left;
2712         left = tmp;
2713     }
2714
2715     /* if right is bit then exchange them */
2716     if (AOP_TYPE(right) == AOP_CRY &&
2717         AOP_TYPE(left) != AOP_CRY){
2718         operand *tmp = right ;
2719         right = left;
2720         left = tmp;
2721     }
2722     if(AOP_TYPE(right) == AOP_LIT)
2723         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2724
2725     size = AOP_SIZE(result);
2726
2727     if (AOP_TYPE(left) == AOP_CRY){
2728         assert(0);
2729         goto release ;
2730     }
2731
2732     if((AOP_TYPE(right) == AOP_LIT) &&
2733        (AOP_TYPE(result) == AOP_CRY) &&
2734        (AOP_TYPE(left) != AOP_CRY)){
2735         assert(0);
2736         goto release ;
2737     }
2738
2739     /* if left is same as result */
2740     if(sameRegs(AOP(result),AOP(left))){
2741         for(;size--; offset++) {
2742             if(AOP_TYPE(right) == AOP_LIT){
2743                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2744                     continue;
2745                 else {
2746                     MOVA(aopGet(AOP(right),offset,FALSE));
2747                     emitcode("xor","a,%s",
2748                              aopGet(AOP(left),offset,FALSE));
2749                     aopPut(AOP(result),"a",0);
2750                 }
2751             } else {
2752                 if (AOP_TYPE(left) == AOP_ACC) 
2753                     emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
2754                 else {              
2755                     MOVA(aopGet(AOP(right),offset,FALSE));
2756                     emitcode("xor","a,%s",
2757                              aopGet(AOP(left),offset,FALSE));
2758                     aopPut(AOP(result),"a",0);
2759                 }
2760             }
2761         }
2762     } else {
2763         // left & result in different registers
2764         if(AOP_TYPE(result) == AOP_CRY){
2765             assert(0);
2766         } else for(;(size--);offset++){
2767             // normal case
2768             // result = left & right
2769             if(AOP_TYPE(right) == AOP_LIT){
2770                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2771                     aopPut(AOP(result),
2772                            aopGet(AOP(left),offset,FALSE),
2773                            offset);
2774                     continue;
2775                 }
2776             }
2777             // faster than result <- left, anl result,right
2778             // and better if result is SFR
2779             if (AOP_TYPE(left) == AOP_ACC) 
2780                 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
2781             else {
2782                 MOVA(aopGet(AOP(right),offset,FALSE));
2783                 emitcode("xor","a,%s",
2784                          aopGet(AOP(left),offset,FALSE));
2785                 aopPut(AOP(result),"a",0);
2786             }
2787             aopPut(AOP(result),"a",offset);                     
2788         }
2789     }
2790
2791 release :
2792     freeAsmop(left,NULL,ic);
2793     freeAsmop(right,NULL,ic);
2794     freeAsmop(result,NULL,ic);
2795 }
2796
2797 /*-----------------------------------------------------------------*/
2798 /* genInline - write the inline code out                           */
2799 /*-----------------------------------------------------------------*/
2800 static void genInline (iCode *ic)
2801 {
2802     char buffer[MAX_INLINEASM];
2803     char *bp = buffer;
2804     char *bp1= buffer;
2805     
2806     inLine += (!options.asmpeep);
2807     strcpy(buffer,IC_INLINE(ic));
2808
2809     /* emit each line as a code */
2810     while (*bp) {
2811         if (*bp == '\n') {
2812             *bp++ = '\0';
2813             emitcode(bp1,"");
2814             bp1 = bp;
2815         } else {
2816             if (*bp == ':') {
2817                 bp++;
2818                 *bp = '\0';
2819                 bp++;
2820                 emitcode(bp1,"");
2821                 bp1 = bp;
2822             } else
2823                 bp++;
2824         }
2825     }
2826     if (bp1 != bp)
2827         emitcode(bp1,"");
2828     /*     emitcode("",buffer); */
2829     inLine -= (!options.asmpeep);
2830 }
2831
2832 /*-----------------------------------------------------------------*/
2833 /* genRRC - rotate right with carry                                */
2834 /*-----------------------------------------------------------------*/
2835 static void genRRC (iCode *ic)
2836 {
2837     assert(0);
2838 }
2839
2840 /*-----------------------------------------------------------------*/
2841 /* genRLC - generate code for rotate left with carry               */
2842 /*-----------------------------------------------------------------*/
2843 static void genRLC (iCode *ic)
2844 {    
2845     assert(0);
2846 }
2847
2848 /*-----------------------------------------------------------------*/
2849 /* shiftR2Left2Result - shift right two bytes from left to result  */
2850 /*-----------------------------------------------------------------*/
2851 static void shiftR2Left2Result (operand *left, int offl,
2852                                 operand *result, int offr,
2853                                 int shCount, int sign)
2854 {
2855     if(sameRegs(AOP(result), AOP(left)) &&
2856        ((offl + MSB16) == offr)){
2857         assert(0);
2858     } else {
2859         movLeft2Result(left, offl, result, offr, 0);
2860         movLeft2Result(left, offl+1, result, offr+1, 0);
2861     }
2862
2863     if (sign) {
2864         assert(0);
2865     }
2866     else {
2867         /*      if (AOP(result)->type == AOP_REG) {*/
2868             int size = 2;
2869             int offset = 0;
2870             symbol *tlbl , *tlbl1;
2871             char *l;
2872
2873             /* Left is already in result - so now do the shift */
2874             if (shCount>1) {
2875                 emitcode("ld","a,#%u+1", shCount);
2876                 tlbl = newiTempLabel(NULL);
2877                 tlbl1 = newiTempLabel(NULL);
2878                 emitcode(_shortJP, LABEL_STR ,tlbl1->key+100); 
2879                 emitcode("", LABEL_STR ":",tlbl->key+100);    
2880             }
2881
2882             emitcode("or", "a,a");
2883             offset = size;
2884             while (size--) {
2885                 l = aopGet(AOP(result), --offset, FALSE);
2886                 emitcode("rr","%s", l);         
2887             }
2888             if (shCount>1) {
2889                 emitcode("", LABEL_STR ":",tlbl1->key+100);
2890                 emitcode("dec", "a");
2891                 emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
2892             }
2893     }
2894 }
2895
2896 /*-----------------------------------------------------------------*/
2897 /* shiftL2Left2Result - shift left two bytes from left to result   */
2898 /*-----------------------------------------------------------------*/
2899 static void shiftL2Left2Result (operand *left, int offl,
2900                                 operand *result, int offr, int shCount)
2901 {
2902     if(sameRegs(AOP(result), AOP(left)) &&
2903        ((offl + MSB16) == offr)){
2904         assert(0);
2905     } else {
2906         /* Copy left into result */
2907         movLeft2Result(left, offl, result, offr, 0);
2908         movLeft2Result(left, offl+1, result, offr+1, 0);
2909     }
2910     /* PENDING: for now just see if it'll work. */
2911     /*if (AOP(result)->type == AOP_REG) { */
2912     {
2913         int size = 2;
2914         int offset = 0;
2915         symbol *tlbl , *tlbl1;
2916         char *l;
2917
2918         /* Left is already in result - so now do the shift */
2919         if (shCount>1) {
2920             emitcode("ld","a,#%u+1", shCount);
2921             tlbl = newiTempLabel(NULL);
2922             tlbl1 = newiTempLabel(NULL);
2923             emitcode(_shortJP, LABEL_STR ,tlbl1->key+100); 
2924             emitcode("", LABEL_STR ":",tlbl->key+100);    
2925         }
2926
2927         emitcode("or", "a,a");
2928         while (size--) {
2929             l = aopGet(AOP(result),offset++,FALSE);
2930             emitcode("rl","%s", l);         
2931         }
2932         if (shCount>1) {
2933             emitcode("", LABEL_STR ":",tlbl1->key+100);
2934             emitcode("dec", "a");
2935             emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
2936         }
2937     }
2938 }
2939
2940 /*-----------------------------------------------------------------*/
2941 /* AccRol - rotate left accumulator by known count                 */
2942 /*-----------------------------------------------------------------*/
2943 static void AccRol (int shCount)
2944 {
2945     shCount &= 0x0007;              // shCount : 0..7
2946     switch(shCount){
2947         case 0 :
2948             break;
2949         case 1 :
2950             emitcode("rl","a");
2951             break;
2952         case 2 :
2953             emitcode("rl","a");
2954             emitcode("rl","a");
2955             break;
2956         case 3 :
2957             emitcode("rl","a");
2958             emitcode("rl","a");
2959             emitcode("rl","a");
2960             break;
2961         case 4 :
2962             emitcode("rl","a");
2963             emitcode("rl","a");
2964             emitcode("rl","a");
2965             emitcode("rl","a");
2966             break;
2967         case 5 :
2968             emitcode("rr","a");
2969             emitcode("rr","a");
2970             emitcode("rr","a");
2971             break;
2972         case 6 :
2973             emitcode("rr","a");
2974             emitcode("rr","a");
2975             break;
2976         case 7 :
2977             emitcode("rr","a");
2978             break;
2979     }
2980 }
2981
2982 /*-----------------------------------------------------------------*/
2983 /* AccLsh - left shift accumulator by known count                  */
2984 /*-----------------------------------------------------------------*/
2985 static void AccLsh (int shCount)
2986 {
2987     if(shCount != 0){
2988         if(shCount == 1)
2989             emitcode("add","a,a");
2990         else 
2991             if(shCount == 2) {
2992             emitcode("add","a,a");
2993             emitcode("add","a,a");
2994         } else {
2995             /* rotate left accumulator */
2996             AccRol(shCount);
2997             /* and kill the lower order bits */
2998             emitcode("and","a,#0x%02x", SLMask[shCount]);
2999         }
3000     }
3001 }
3002
3003 /*-----------------------------------------------------------------*/
3004 /* shiftL1Left2Result - shift left one byte from left to result    */
3005 /*-----------------------------------------------------------------*/
3006 static void shiftL1Left2Result (operand *left, int offl,
3007                                 operand *result, int offr, int shCount)
3008 {
3009     char *l;
3010     l = aopGet(AOP(left),offl,FALSE);
3011     MOVA(l);
3012     /* shift left accumulator */
3013     AccLsh(shCount);
3014     aopPut(AOP(result),"a",offr);
3015 }
3016
3017
3018 /*-----------------------------------------------------------------*/
3019 /* genlshTwo - left shift two bytes by known amount != 0           */
3020 /*-----------------------------------------------------------------*/
3021 static void genlshTwo (operand *result,operand *left, int shCount)
3022 {
3023     int size = AOP_SIZE(result);
3024
3025     assert(size==2);
3026
3027     /* if shCount >= 8 */
3028     if (shCount >= 8) {
3029         shCount -= 8 ;
3030
3031         if (size > 1){
3032             if (shCount) {
3033                 movLeft2Result(left, LSB, result, MSB16, 0);
3034                 aopPut(AOP(result),zero, 0);   
3035                 shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
3036             }
3037             else {
3038                 movLeft2Result(left, LSB, result, MSB16, 0);
3039                 aopPut(AOP(result),zero, 0);   
3040             }
3041         }
3042         aopPut(AOP(result),zero,LSB);   
3043     }
3044     /*  1 <= shCount <= 7 */
3045     else {  
3046         if(size == 1) {
3047             assert(0);
3048         }
3049         else {
3050             shiftL2Left2Result(left, LSB, result, LSB, shCount);
3051         }
3052     }
3053 }
3054
3055 /*-----------------------------------------------------------------*/
3056 /* genlshOne - left shift a one byte quantity by known count       */
3057 /*-----------------------------------------------------------------*/
3058 static void genlshOne (operand *result, operand *left, int shCount)
3059 {       
3060     shiftL1Left2Result(left, LSB, result, LSB, shCount);
3061 }
3062
3063 /*-----------------------------------------------------------------*/
3064 /* genLeftShiftLiteral - left shifting by known count              */
3065 /*-----------------------------------------------------------------*/
3066 static void genLeftShiftLiteral (operand *left,
3067                                  operand *right,
3068                                  operand *result,
3069                                  iCode *ic)
3070 {    
3071     int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3072     int size;
3073
3074     freeAsmop(right,NULL,ic);
3075
3076     aopOp(left,ic,FALSE);
3077     aopOp(result,ic,FALSE);
3078
3079     size = getSize(operandType(result));
3080
3081 #if VIEW_SIZE
3082     emitcode("; shift left ","result %d, left %d",size,
3083              AOP_SIZE(left));
3084 #endif
3085
3086     /* I suppose that the left size >= result size */
3087     if (shCount == 0) {
3088         assert(0);
3089     }
3090
3091     else if(shCount >= (size * 8))
3092         while(size--)
3093             aopPut(AOP(result),zero,size);
3094     else{
3095         switch (size) {
3096         case 1:
3097             genlshOne (result,left,shCount);
3098             break;
3099         case 2:
3100             genlshTwo (result,left,shCount);
3101             break;
3102         case 4:
3103             assert(0);
3104             break;
3105         default:
3106             assert(0);
3107         }
3108     }
3109     freeAsmop(left,NULL,ic);
3110     freeAsmop(result,NULL,ic);
3111 }
3112
3113 /*-----------------------------------------------------------------*/
3114 /* genLeftShift - generates code for left shifting                 */
3115 /*-----------------------------------------------------------------*/
3116 static void genLeftShift (iCode *ic)
3117 {
3118     int size, offset;
3119     char *l;
3120     symbol *tlbl , *tlbl1;
3121     operand *left,*right, *result;
3122
3123     right = IC_RIGHT(ic);
3124     left  = IC_LEFT(ic);
3125     result = IC_RESULT(ic);
3126
3127     aopOp(right,ic,FALSE);
3128
3129     /* if the shift count is known then do it 
3130     as efficiently as possible */
3131     if (AOP_TYPE(right) == AOP_LIT) {
3132         genLeftShiftLiteral (left,right,result,ic);
3133         return ;
3134     }
3135
3136     /* shift count is unknown then we have to form a loop get the loop
3137        count in B : Note: we take only the lower order byte since
3138        shifting more that 32 bits make no sense anyway, ( the largest
3139        size of an object can be only 32 bits ) */
3140     emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3141     emitcode("inc","a");
3142     freeAsmop (right,NULL,ic);
3143     aopOp(left,ic,FALSE);
3144     aopOp(result,ic,FALSE);
3145
3146     /* now move the left to the result if they are not the
3147        same */
3148 #if 1
3149     if (!sameRegs(AOP(left),AOP(result))) {
3150
3151         size = AOP_SIZE(result);
3152         offset = 0;
3153         while (size--) {
3154             l = aopGet(AOP(left),offset,FALSE);
3155             aopPut(AOP(result),l,offset);
3156             offset++;
3157         }
3158     }
3159 #else
3160     size = AOP_SIZE(result);
3161     offset = 0;
3162     while (size--) {
3163         l = aopGet(AOP(left),offset,FALSE);
3164         aopPut(AOP(result),l,offset);
3165         offset++;
3166     }
3167 #endif
3168
3169
3170     tlbl = newiTempLabel(NULL);
3171     size = AOP_SIZE(result);
3172     offset = 0 ;   
3173     tlbl1 = newiTempLabel(NULL);
3174
3175     emitcode(_shortJP, LABEL_STR ,tlbl1->key+100); 
3176     emitcode("", LABEL_STR ":",tlbl->key+100);    
3177     l = aopGet(AOP(result),offset,FALSE);
3178     emitcode("or", "a,a");
3179     while (size--) {
3180         l = aopGet(AOP(result),offset++,FALSE);
3181         emitcode("rl","%s", l);         
3182     }
3183     emitcode("", LABEL_STR ":",tlbl1->key+100);
3184     emitcode("dec", "a");
3185     emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
3186
3187     freeAsmop(left,NULL,ic);
3188     freeAsmop(result,NULL,ic);
3189 }
3190
3191 /* genlshTwo - left shift two bytes by known amount != 0           */
3192 /*-----------------------------------------------------------------*/
3193 static void genrshOne (operand *result,operand *left, int shCount)
3194 {
3195     /* Errk */
3196     int size = AOP_SIZE(result);
3197     char *l;
3198
3199     assert(size==1);
3200     assert(shCount<8);
3201
3202     l = aopGet(AOP(left),0,FALSE);
3203     if (AOP(result)->type == AOP_REG) {
3204         aopPut(AOP(result), l, 0);
3205         l = aopGet(AOP(result), 0, FALSE);
3206         while (shCount--) 
3207             emitcode("srl", "%s", l);
3208     }
3209     else {
3210         MOVA(l);
3211         while (shCount--) {
3212             emitcode("srl", "a");
3213         }
3214         aopPut(AOP(result),"a",0);
3215     }
3216 }
3217
3218 /*-----------------------------------------------------------------*/
3219 /* AccRsh - right shift accumulator by known count                 */
3220 /*-----------------------------------------------------------------*/
3221 static void AccRsh (int shCount)
3222 {
3223     if(shCount != 0){
3224         if(shCount == 1){
3225             CLRC;
3226             emitcode("rr","a");
3227         } else {
3228             /* rotate right accumulator */
3229             AccRol(8 - shCount);
3230             /* and kill the higher order bits */
3231             emitcode("and","a,#0x%02x", SRMask[shCount]);
3232         }
3233     }
3234 }
3235
3236 /*-----------------------------------------------------------------*/
3237 /* shiftR1Left2Result - shift right one byte from left to result   */
3238 /*-----------------------------------------------------------------*/
3239 static void shiftR1Left2Result (operand *left, int offl,
3240                                 operand *result, int offr,
3241                                 int shCount, int sign)
3242 {
3243     MOVA(aopGet(AOP(left),offl,FALSE));
3244     if (sign) {
3245         assert(0);
3246     }
3247     else {
3248         AccRsh(shCount);
3249     }
3250     aopPut(AOP(result),"a",offr);
3251 }
3252
3253 /*-----------------------------------------------------------------*/
3254 /* genrshTwo - right shift two bytes by known amount != 0          */
3255 /*-----------------------------------------------------------------*/
3256 static void genrshTwo (operand *result,operand *left,
3257                        int shCount, int sign)
3258 {
3259     /* if shCount >= 8 */
3260     if (shCount >= 8) {
3261         shCount -= 8 ;
3262         if (shCount) {
3263             assert(0);
3264             shiftR1Left2Result(left, MSB16, result, LSB,
3265                                shCount, sign);
3266         }
3267         else {
3268             movLeft2Result(left, MSB16, result, LSB, sign);
3269             aopPut(AOP(result),zero,1);
3270         }
3271     }
3272     /*  1 <= shCount <= 7 */
3273     else {
3274         shiftR2Left2Result(left, LSB, result, LSB, shCount, sign); 
3275     }
3276 }
3277
3278 /*-----------------------------------------------------------------*/
3279 /* genRightShiftLiteral - left shifting by known count              */
3280 /*-----------------------------------------------------------------*/
3281 static void genRightShiftLiteral (operand *left,
3282                                  operand *right,
3283                                  operand *result,
3284                                  iCode *ic)
3285 {    
3286     int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3287     int size;
3288
3289     freeAsmop(right,NULL,ic);
3290
3291     aopOp(left,ic,FALSE);
3292     aopOp(result,ic,FALSE);
3293
3294     size = getSize(operandType(result));
3295
3296     emitcode("; shift right ","result %d, left %d",size,
3297              AOP_SIZE(left));
3298
3299     /* I suppose that the left size >= result size */
3300     if (shCount == 0) {
3301         assert(0);
3302     }
3303
3304     else if(shCount >= (size * 8))
3305         while(size--)
3306             aopPut(AOP(result),zero,size);
3307     else{
3308         switch (size) {
3309         case 1:
3310             genrshOne(result, left, shCount);
3311             break;
3312         case 2:
3313             /* PENDING: sign support */
3314             genrshTwo(result, left, shCount, FALSE);
3315             break;
3316         case 4:
3317             assert(0);
3318             break;
3319         default:
3320             assert(0);
3321         }
3322     }
3323     freeAsmop(left,NULL,ic);
3324     freeAsmop(result,NULL,ic);
3325 }
3326
3327 /*-----------------------------------------------------------------*/
3328 /* genRightShift - generate code for right shifting                */
3329 /*-----------------------------------------------------------------*/
3330 static void genRightShift (iCode *ic)
3331 {
3332     operand *left,*right, *result;
3333
3334     right = IC_RIGHT(ic);
3335     left  = IC_LEFT(ic);
3336     result = IC_RESULT(ic);
3337
3338     aopOp(right,ic,FALSE);
3339
3340     /* if the shift count is known then do it 
3341     as efficiently as possible */
3342     if (AOP_TYPE(right) == AOP_LIT) {
3343         genRightShiftLiteral (left,right,result,ic);
3344         return ;
3345     }
3346     else {
3347         assert(0);
3348     }
3349 }
3350
3351 /*-----------------------------------------------------------------*/
3352 /* genGenPointerGet - gget value from generic pointer space        */
3353 /*-----------------------------------------------------------------*/
3354 static void genGenPointerGet (operand *left,
3355                               operand *result, iCode *ic)
3356 {
3357     int size, offset ;
3358     link *retype = getSpec(operandType(result));
3359     const char *ptr = "hl";
3360
3361     if (IS_GB)
3362         ptr = "de";
3363
3364     aopOp(left,ic,FALSE);
3365     aopOp(result,ic,FALSE);
3366
3367     if (isPair(AOP(left)) && (AOP_SIZE(result)==1)) {
3368         /* Just do it */
3369         emitcode("ld", "a,(%s)", getPairName(AOP(left)));
3370         aopPut(AOP(result),"a", 0);
3371         freeAsmop(left,NULL,ic);
3372         goto release;
3373     }
3374
3375     /* For now we always load into IY */
3376     /* if this is remateriazable */
3377     if (AOP_TYPE(left) == AOP_IMMD)
3378         emitcode("ld","%s,%s", ptr, aopGet(AOP(left),0,TRUE));
3379     else { /* we need to get it byte by byte */
3380         if (IS_GB) {
3381             emitcode("ld", "e,%s", aopGet(AOP(left), 0, FALSE));
3382             emitcode("ld", "d,%s", aopGet(AOP(left), 1, FALSE));
3383         }
3384         else
3385             fetchHL(AOP(left));
3386     }
3387     /* so iy now contains the address */
3388     freeAsmop(left,NULL,ic);
3389
3390     /* if bit then unpack */
3391     if (IS_BITVAR(retype)) {
3392         assert(0);
3393     }
3394     else {
3395         size = AOP_SIZE(result);
3396         offset = 0 ;
3397
3398         while (size--) {
3399             /* PENDING: make this better */
3400             if (!IS_GB && AOP(result)->type == AOP_REG) {
3401                 aopPut(AOP(result),"(hl)",offset++);
3402             }
3403             else {
3404                 emitcode("ld", "a,(%s)", ptr, offset);
3405                 aopPut(AOP(result),"a",offset++);
3406             }
3407             if (size) {
3408                 emitcode("inc", "%s", ptr);
3409             }
3410         }
3411     }
3412
3413  release:
3414     freeAsmop(result,NULL,ic);
3415 }
3416
3417 /*-----------------------------------------------------------------*/
3418 /* genPointerGet - generate code for pointer get                   */
3419 /*-----------------------------------------------------------------*/
3420 static void genPointerGet (iCode *ic)
3421 {
3422     operand *left, *result ;
3423     link *type, *etype;
3424
3425     left = IC_LEFT(ic);
3426     result = IC_RESULT(ic) ;
3427
3428     /* depending on the type of pointer we need to
3429     move it to the correct pointer register */
3430     type = operandType(left);
3431     etype = getSpec(type);
3432
3433     genGenPointerGet (left,result,ic);
3434 }
3435
3436 bool isRegOrLit(asmop *aop)
3437 {
3438     if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3439         return TRUE;
3440     return FALSE;
3441 }
3442
3443 /*-----------------------------------------------------------------*/
3444 /* genGenPointerSet - stores the value into a pointer location        */
3445 /*-----------------------------------------------------------------*/
3446 static void genGenPointerSet (operand *right,
3447                               operand *result, iCode *ic)
3448 {    
3449     int size, offset ;
3450     link *retype = getSpec(operandType(right));
3451     const char *ptr = "hl";
3452
3453     aopOp(result,ic,FALSE);
3454     aopOp(right,ic,FALSE);
3455
3456     if (IS_GB)
3457         ptr = "de";
3458
3459     /* Handle the exceptions first */
3460     if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3461         /* Just do it */
3462         char *l = aopGet(AOP(right), 0, FALSE);
3463         MOVA(l);
3464         emitcode("ld", "(%s),a", getPairName(AOP(result)));
3465         freeAsmop(result,NULL,ic);
3466         goto release;
3467     }
3468         
3469     /* if the operand is already in dptr 
3470        then we do nothing else we move the value to dptr */
3471     if (AOP_TYPE(result) != AOP_STR) {
3472         /* if this is remateriazable */
3473         if (AOP_TYPE(result) == AOP_IMMD) {
3474             emitcode("", "; Error 2");
3475             emitcode("ld", "%s,%s", ptr, aopGet(AOP(result), 0, TRUE));
3476         }
3477         else { /* we need to get it byte by byte */
3478             if (IS_GB) {
3479                 emitcode("ld", "e,%s", aopGet(AOP(result), 0, TRUE));
3480                 emitcode("ld", "d,%s", aopGet(AOP(result), 1, TRUE));
3481             }
3482             else {
3483                 /* PENDING: do this better */
3484                 fetchHL(AOP(result));
3485             }
3486         }
3487     }
3488     /* so hl know contains the address */
3489     freeAsmop(result,NULL,ic);
3490
3491     /* if bit then unpack */
3492     if (IS_BITVAR(retype)) {
3493         assert(0);
3494     }
3495     else {
3496         size = AOP_SIZE(right);
3497         offset = 0 ;
3498
3499         while (size--) {
3500             char *l = aopGet(AOP(right),offset,FALSE);
3501             if (isRegOrLit(AOP(right)) && !IS_GB) {
3502                 emitcode("ld", "(%s),%s", l);
3503             }
3504             else {
3505                 MOVA(l);
3506                 emitcode("ld", "(%s),a", ptr, offset);
3507             }
3508             if (size) {
3509                 emitcode("inc", ptr);
3510             }
3511             offset++;
3512         }
3513     }
3514     release:
3515     freeAsmop(right,NULL,ic);
3516 }
3517
3518 /*-----------------------------------------------------------------*/
3519 /* genPointerSet - stores the value into a pointer location        */
3520 /*-----------------------------------------------------------------*/
3521 static void genPointerSet (iCode *ic)
3522 {    
3523     operand *right, *result ;
3524     link *type, *etype;
3525
3526     right = IC_RIGHT(ic);
3527     result = IC_RESULT(ic) ;
3528
3529     /* depending on the type of pointer we need to
3530     move it to the correct pointer register */
3531     type = operandType(result);
3532     etype = getSpec(type);
3533     
3534     genGenPointerSet (right,result,ic);
3535 }
3536
3537 /*-----------------------------------------------------------------*/
3538 /* genIfx - generate code for Ifx statement                        */
3539 /*-----------------------------------------------------------------*/
3540 static void genIfx (iCode *ic, iCode *popIc)
3541 {
3542     operand *cond = IC_COND(ic);
3543     int isbit =0;
3544
3545     aopOp(cond,ic,FALSE);
3546
3547     /* get the value into acc */
3548     if (AOP_TYPE(cond) != AOP_CRY)
3549         toBoolean(cond);
3550     else
3551         isbit = 1;
3552     /* the result is now in the accumulator */
3553     freeAsmop(cond,NULL,ic);
3554
3555     /* if there was something to be popped then do it */
3556     if (popIc)
3557         genIpop(popIc);
3558
3559     /* if the condition is  a bit variable */
3560     if (isbit && IS_ITEMP(cond) && 
3561         SPIL_LOC(cond))
3562         genIfxJump(ic,SPIL_LOC(cond)->rname);
3563     else
3564         if (isbit && !IS_ITEMP(cond))
3565             genIfxJump(ic,OP_SYMBOL(cond)->rname);
3566         else
3567             genIfxJump(ic,"a");
3568
3569     ic->generated = 1;
3570 }
3571
3572 /*-----------------------------------------------------------------*/
3573 /* genAddrOf - generates code for address of                       */
3574 /*-----------------------------------------------------------------*/
3575 static void genAddrOf (iCode *ic)
3576 {
3577     symbol *sym = OP_SYMBOL(IC_LEFT(ic));
3578
3579     aopOp(IC_RESULT(ic),ic,FALSE);
3580
3581     /* if the operand is on the stack then we 
3582     need to get the stack offset of this
3583     variable */
3584     if (sym->onStack) {
3585         /* if it has an offset  then we need to compute it */
3586         if (IS_GB) {
3587             emitcode("lda", "hl,%d+%d+%d(sp)", sym->stack, _pushed, _spoffset);
3588             emitcode("ld", "d,h");
3589             emitcode("ld", "e,l");
3590             aopPut(AOP(IC_RESULT(ic)), "e", 0);
3591             aopPut(AOP(IC_RESULT(ic)), "d", 1);
3592             goto end;
3593         }
3594         else {
3595             emitcode("push", "de");
3596             emitcode("push", "ix");
3597             emitcode("pop", "hl");
3598             emitcode("ld", "de,#%d", sym->stack);
3599             emitcode("add", "hl,de");
3600             emitcode("pop", "de");
3601         }
3602     }
3603     else {
3604         emitcode("ld", "hl,#%s", sym->rname);
3605     }
3606     aopPut(AOP(IC_RESULT(ic)), "l", 0);
3607     aopPut(AOP(IC_RESULT(ic)), "h", 1);
3608 end:
3609     freeAsmop(IC_RESULT(ic),NULL,ic);
3610 }
3611
3612 /*-----------------------------------------------------------------*/
3613 /* genAssign - generate code for assignment                        */
3614 /*-----------------------------------------------------------------*/
3615 static void genAssign (iCode *ic)
3616 {
3617     operand *result, *right;
3618     int size, offset ;
3619     unsigned long lit = 0L;
3620
3621     result = IC_RESULT(ic);
3622     right  = IC_RIGHT(ic) ;
3623
3624 #if 1
3625     /* Dont bother assigning if they are the same */
3626     if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
3627         emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
3628         return;
3629     }
3630 #endif
3631
3632     aopOp(right,ic,FALSE);
3633     aopOp(result,ic,TRUE);
3634
3635     /* if they are the same registers */
3636     if (sameRegs(AOP(right),AOP(result))) {
3637         emitcode("", "; (registers are the same)");
3638         goto release;
3639     }
3640
3641     /* if the result is a bit */
3642     if (AOP_TYPE(result) == AOP_CRY) {
3643         assert(0);
3644     }
3645
3646     /* general case */
3647     size = AOP_SIZE(result);
3648     offset = 0;
3649
3650     if(AOP_TYPE(right) == AOP_LIT)
3651         lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
3652     if((size > 1) &&
3653        (AOP_TYPE(result) != AOP_REG) &&
3654        (AOP_TYPE(right) == AOP_LIT) &&
3655        !IS_FLOAT(operandType(right)) &&
3656        (lit < 256L)) {
3657         bool fXored = FALSE;
3658         offset = 0;
3659         /* Work from the top down.
3660            Done this way so that we can use the cached copy of 0
3661            in A for a fast clear */
3662         while (size--) {
3663             if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
3664                 if (!fXored && size>1) {
3665                     emitcode("xor", "a,a");
3666                     fXored = TRUE;
3667                 }
3668                 if (fXored) {
3669                     aopPut(AOP(result),"a",offset);
3670                 }
3671                 else {
3672                     aopPut(AOP(result), "#0", offset);
3673                 }
3674             }
3675             else
3676                 aopPut(AOP(result),
3677                        aopGet(AOP(right),offset,FALSE),
3678                        offset);
3679             offset++;
3680         }
3681     }
3682     else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result))) {
3683         /* Special case.  Load into a and d, then load out. */
3684         MOVA(aopGet(AOP(right), 0, FALSE));
3685         emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
3686         aopPut(AOP(result), "a", 0);
3687         aopPut(AOP(result), "e", 1);
3688     } else {
3689         while (size--) {
3690             aopPut(AOP(result),
3691                    aopGet(AOP(right),offset,FALSE),
3692                    offset);
3693             offset++;
3694         }
3695     }
3696     
3697 release:
3698     freeAsmop(right,NULL,ic);
3699     freeAsmop(result,NULL,ic);
3700 }   
3701
3702 /*-----------------------------------------------------------------*/
3703 /* genJumpTab - genrates code for jump table                       */
3704 /*-----------------------------------------------------------------*/
3705 static void genJumpTab (iCode *ic)
3706 {
3707     symbol *jtab;
3708     char *l;
3709
3710     aopOp(IC_JTCOND(ic),ic,FALSE);
3711     /* get the condition into accumulator */
3712     l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
3713     MOVA(l);
3714     if (!IS_GB)
3715         emitcode("push", "de");
3716     emitcode("ld", "e,%s", l);
3717     emitcode("ld", "d,#0");
3718     jtab = newiTempLabel(NULL);
3719     emitcode("ld", "hl,#" LABEL_STR, jtab->key+100);
3720     emitcode("add", "hl,de");
3721     emitcode("add", "hl,de");
3722     emitcode("add", "hl,de");
3723     freeAsmop(IC_JTCOND(ic),NULL,ic);
3724     if (!IS_GB)
3725         emitcode("pop", "de");
3726     emitcode("jp", "(hl)");
3727     emitcode("","%05d$:",jtab->key+100);
3728     /* now generate the jump labels */
3729     for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
3730          jtab = setNextItem(IC_JTLABELS(ic)))
3731         emitcode("jp", LABEL_STR, jtab->key+100);
3732 }
3733
3734 /*-----------------------------------------------------------------*/
3735 /* genCast - gen code for casting                                  */
3736 /*-----------------------------------------------------------------*/
3737 static void genCast (iCode *ic)
3738 {
3739     operand *result = IC_RESULT(ic);
3740     link *ctype = operandType(IC_LEFT(ic));
3741     operand *right = IC_RIGHT(ic);
3742     int size, offset ;
3743
3744     /* if they are equivalent then do nothing */
3745     if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
3746         return ;
3747
3748     aopOp(right,ic,FALSE) ;
3749     aopOp(result,ic,FALSE);
3750
3751     /* if the result is a bit */
3752     if (AOP_TYPE(result) == AOP_CRY) {
3753         assert(0);
3754     }
3755
3756     /* if they are the same size : or less */
3757     if (AOP_SIZE(result) <= AOP_SIZE(right)) {
3758
3759         /* if they are in the same place */
3760         if (sameRegs(AOP(right),AOP(result)))
3761             goto release;
3762
3763         /* if they in different places then copy */
3764         size = AOP_SIZE(result);
3765         offset = 0 ;
3766         while (size--) {
3767             aopPut(AOP(result),
3768                    aopGet(AOP(right),offset,FALSE),
3769                    offset);
3770             offset++;
3771         }
3772         goto release;
3773     }
3774
3775     /* PENDING: should be OK. */
3776 #if 0
3777     /* if the result is of type pointer */
3778     if (IS_PTR(ctype)) {
3779         assert(0);
3780     }
3781 #endif
3782     
3783     /* so we now know that the size of destination is greater
3784     than the size of the source */
3785     /* we move to result for the size of source */
3786     size = AOP_SIZE(right);
3787     offset = 0 ;
3788     while (size--) {
3789         aopPut(AOP(result),
3790                aopGet(AOP(right),offset,FALSE),
3791                offset);
3792         offset++;
3793     }
3794
3795     /* now depending on the sign of the destination */
3796     size = AOP_SIZE(result) - AOP_SIZE(right);
3797     /* Unsigned or not an integral type - right fill with zeros */
3798     if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
3799         while (size--)
3800             aopPut(AOP(result),zero,offset++);
3801     } else {
3802         /* we need to extend the sign :{ */
3803         char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
3804                          FALSE);
3805         MOVA(l);
3806         emitcode("", "; genCast: sign extend untested.");
3807         emitcode("rla", "");
3808         emitcode("sbc", "a,a");
3809         while (size--)
3810             aopPut(AOP(result),"a",offset++);   
3811     }
3812
3813 release:
3814     freeAsmop(right, NULL, ic);
3815     freeAsmop(result, NULL, ic);
3816 }
3817
3818 /*-----------------------------------------------------------------*/
3819 /* genReceive - generate code for a receive iCode                  */
3820 /*-----------------------------------------------------------------*/
3821 static void genReceive (iCode *ic)
3822 {    
3823     if (isOperandInFarSpace(IC_RESULT(ic)) && 
3824         ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
3825           IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
3826         assert(0);
3827     } else {
3828         accInUse++;
3829         aopOp(IC_RESULT(ic),ic,FALSE);  
3830         accInUse--;
3831         assignResultValue(IC_RESULT(ic));       
3832     }
3833
3834     freeAsmop(IC_RESULT(ic),NULL,ic);
3835 }
3836
3837 /*-----------------------------------------------------------------*/
3838 /* genZ80Code - generate code for Z80 based controllers            */
3839 /*-----------------------------------------------------------------*/
3840 void genZ80Code (iCode *lic)
3841 {
3842     iCode *ic;
3843     int cln = 0;
3844
3845     /* HACK */
3846     if (IS_GB) {
3847         _fReturn = _gbz80_return;
3848         _fTmp = _gbz80_return;
3849         _shortJP = "jr";
3850     }
3851     else {
3852         _fReturn = _z80_return;
3853         _fTmp = _z80_return;
3854         _shortJP = "jp";
3855     }
3856
3857     lineHead = lineCurr = NULL;
3858
3859     /* if debug information required */
3860     if (options.debug && currFunc) { 
3861         cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
3862         debugLine = 1;
3863         if (IS_STATIC(currFunc->etype))
3864             emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name); 
3865         else
3866             emitcode("","G$%s$0$0 ==.",currFunc->name);
3867         debugLine = 0;
3868     }
3869     /* stack pointer name */
3870     spname = "sp";
3871     
3872  
3873     for (ic = lic ; ic ; ic = ic->next ) {
3874         
3875         if ( cln != ic->lineno ) {
3876             if ( options.debug ) {
3877                 debugLine = 1;
3878                 emitcode("","C$%s$%d$%d$%d ==.",
3879                          ic->filename,ic->lineno,
3880                          ic->level,ic->block);
3881                 debugLine = 0;
3882             }
3883             emitcode(";","%s %d",ic->filename,ic->lineno);
3884             cln = ic->lineno ;
3885         }
3886         /* if the result is marked as
3887            spilt and rematerializable or code for
3888            this has already been generated then
3889            do nothing */
3890         if (resultRemat(ic) || ic->generated ) 
3891             continue ;
3892         
3893         /* depending on the operation */
3894         switch (ic->op) {
3895         case '!' :
3896             emitcode("", "; genNot");
3897             genNot(ic);
3898             break;
3899             
3900         case '~' :
3901             emitcode("", "; genCpl");
3902             genCpl(ic);
3903             break;
3904             
3905         case UNARYMINUS:
3906             emitcode("", "; genUminus");
3907             genUminus (ic);
3908             break;
3909             
3910         case IPUSH:
3911             emitcode("", "; genIpush");
3912             genIpush (ic);
3913             break;
3914             
3915         case IPOP:
3916             /* IPOP happens only when trying to restore a 
3917                spilt live range, if there is an ifx statement
3918                following this pop then the if statement might
3919                be using some of the registers being popped which
3920                would destory the contents of the register so
3921                we need to check for this condition and handle it */
3922             if (ic->next            && 
3923                 ic->next->op == IFX &&
3924                 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
3925                 emitcode("", "; genIfx");
3926                 genIfx (ic->next,ic);
3927             }
3928             else {
3929                 emitcode("", "; genIpop");
3930                 genIpop (ic);
3931             }
3932             break; 
3933             
3934         case CALL:
3935             emitcode("", "; genCall");
3936             genCall (ic);
3937             break;
3938             
3939         case PCALL:
3940             emitcode("", "; genPcall");
3941             genPcall (ic);
3942             break;
3943             
3944         case FUNCTION:
3945             emitcode("", "; genFunction");
3946             genFunction (ic);
3947             break;
3948             
3949         case ENDFUNCTION:
3950             emitcode("", "; genEndFunction");
3951             genEndFunction (ic);
3952             break;
3953             
3954         case RETURN:
3955             emitcode("", "; genRet");
3956             genRet (ic);
3957             break;
3958             
3959         case LABEL:
3960             emitcode("", "; genLabel");
3961             genLabel (ic);
3962             break;
3963             
3964         case GOTO:
3965             emitcode("", "; genGoto");
3966             genGoto (ic);
3967             break;
3968             
3969         case '+' :
3970             emitcode("", "; genPlus");
3971             genPlus (ic) ;
3972             break;
3973             
3974         case '-' :
3975             emitcode("", "; genMinus");
3976             genMinus (ic);
3977             break;
3978             
3979         case '*' :
3980             emitcode("", "; genMult");
3981             genMult (ic);
3982             break;
3983             
3984         case '/' :
3985             emitcode("", "; genDiv");
3986             genDiv (ic) ;
3987             break;
3988             
3989         case '%' :
3990             emitcode("", "; genMod");
3991             genMod (ic);
3992             break;
3993             
3994         case '>' :
3995             emitcode("", "; genCmpGt");
3996             genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));                 
3997             break;
3998             
3999         case '<' :
4000             emitcode("", "; genCmpLt");
4001             genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4002             break;
4003             
4004         case LE_OP:
4005         case GE_OP:
4006         case NE_OP:
4007             
4008             /* note these two are xlated by algebraic equivalence
4009                during parsing SDCC.y */
4010             werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4011                    "got '>=' or '<=' shouldn't have come here");
4012             break;      
4013             
4014         case EQ_OP:
4015             emitcode("", "; genCmpEq");
4016             genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4017             break;          
4018             
4019         case AND_OP:
4020             emitcode("", "; genAndOp");
4021             genAndOp (ic);
4022             break;
4023             
4024         case OR_OP:
4025             emitcode("", "; genOrOp");
4026             genOrOp (ic);
4027             break;
4028             
4029         case '^' :
4030             emitcode("", "; genXor");
4031             genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4032             break;
4033             
4034         case '|' :
4035             emitcode("", "; genOr");
4036             genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4037             break;
4038             
4039         case BITWISEAND:
4040             emitcode("", "; genAnd");
4041             genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4042             break;
4043             
4044         case INLINEASM:
4045             emitcode("", "; genInline");
4046             genInline (ic);
4047             break;
4048             
4049         case RRC:
4050             emitcode("", "; genRRC");
4051             genRRC (ic);
4052             break;
4053             
4054         case RLC:
4055             emitcode("", "; genRLC");
4056             genRLC (ic);
4057             break;
4058             
4059         case GETHBIT:
4060             emitcode("", "; genHBIT");
4061             assert(0);
4062             
4063         case LEFT_OP:
4064             emitcode("", "; genLeftShift");
4065             genLeftShift (ic);
4066             break;
4067             
4068         case RIGHT_OP:
4069             emitcode("", "; genRightShift");
4070             genRightShift (ic);
4071             break;
4072             
4073         case GET_VALUE_AT_ADDRESS:
4074             emitcode("", "; genPointerGet");
4075             genPointerGet(ic);
4076             break;
4077             
4078         case '=' :
4079
4080             if (POINTER_SET(ic)) {
4081                 emitcode("", "; genAssign (pointer)");
4082                 genPointerSet(ic);
4083             }
4084             else {
4085                 emitcode("", "; genAssign");
4086                 genAssign(ic);
4087             }
4088             break;
4089             
4090         case IFX:
4091             emitcode("", "; genIfx");
4092             genIfx (ic,NULL);
4093             break;
4094             
4095         case ADDRESS_OF:
4096             emitcode("", "; genAddrOf");
4097             genAddrOf (ic);
4098             break;
4099             
4100         case JUMPTABLE:
4101             emitcode("", "; genJumpTab");
4102             genJumpTab (ic);
4103             break;
4104             
4105         case CAST:
4106             emitcode("", "; genCast");
4107             genCast (ic);
4108             break;
4109             
4110         case RECEIVE:
4111             emitcode("", "; genReceive");
4112             genReceive(ic);
4113             break;
4114             
4115         case SEND:
4116             emitcode("", "; addSet");
4117             addSet(&sendSet,ic);
4118             break;
4119
4120         default :
4121             ic = ic;
4122             /*      piCode(ic,stdout); */
4123             
4124         }
4125     }
4126     
4127
4128     /* now we are ready to call the 
4129        peep hole optimizer */
4130     if (!options.nopeep)
4131         peepHole (&lineHead);
4132
4133     /* now do the actual printing */
4134     printLine (lineHead,codeOutFile);
4135     return;
4136 }