Lots.
[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 /* jmpTrueOrFalse -                                                */
2377 /*-----------------------------------------------------------------*/
2378 static void jmpTrueOrFalse (iCode *ic, symbol *tlbl)
2379 {
2380     // ugly but optimized by peephole
2381     if(IC_TRUE(ic)){
2382         symbol *nlbl = newiTempLabel(NULL);
2383         emitcode("jp", LABEL_STR, nlbl->key+100);                 
2384         emitcode("", LABEL_STR ":",tlbl->key+100);
2385         emitcode("jp",LABEL_STR,IC_TRUE(ic)->key+100);
2386         emitcode("", LABEL_STR ":",nlbl->key+100);
2387     }
2388     else{
2389         emitcode("jp", LABEL_STR, IC_FALSE(ic)->key+100);
2390         emitcode("", LABEL_STR ":",tlbl->key+100);
2391     }
2392     ic->generated = 1;
2393 }
2394
2395 /*-----------------------------------------------------------------*/
2396 /* genAnd  - code for and                                          */
2397 /*-----------------------------------------------------------------*/
2398 static void genAnd (iCode *ic, iCode *ifx)
2399 {
2400     operand *left, *right, *result;
2401     int size, offset=0;  
2402     unsigned long lit = 0L;
2403     int bytelit = 0;
2404
2405     aopOp((left = IC_LEFT(ic)),ic,FALSE);
2406     aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2407     aopOp((result=IC_RESULT(ic)),ic,TRUE);
2408
2409 #ifdef DEBUG_TYPE
2410     emitcode("","; Type res[%d] = l[%d]&r[%d]",
2411              AOP_TYPE(result),
2412              AOP_TYPE(left), AOP_TYPE(right));
2413     emitcode("","; Size res[%d] = l[%d]&r[%d]",
2414              AOP_SIZE(result),
2415              AOP_SIZE(left), AOP_SIZE(right));
2416 #endif
2417
2418     /* if left is a literal & right is not then exchange them */
2419     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2420         AOP_NEEDSACC(left)) {
2421         operand *tmp = right ;
2422         right = left;
2423         left = tmp;
2424     }
2425
2426     /* if result = right then exchange them */
2427     if(sameRegs(AOP(result),AOP(right))){
2428         operand *tmp = right ;
2429         right = left;
2430         left = tmp;
2431     }
2432
2433     /* if right is bit then exchange them */
2434     if (AOP_TYPE(right) == AOP_CRY &&
2435         AOP_TYPE(left) != AOP_CRY){
2436         operand *tmp = right ;
2437         right = left;
2438         left = tmp;
2439     }
2440     if(AOP_TYPE(right) == AOP_LIT)
2441         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2442
2443     size = AOP_SIZE(result);
2444
2445     if (AOP_TYPE(left) == AOP_CRY){
2446         assert(0);
2447         goto release ;
2448     }
2449
2450     // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
2451     // bit = val & 0xZZ     - size = 1, ifx = FALSE -
2452     if((AOP_TYPE(right) == AOP_LIT) &&
2453        (AOP_TYPE(result) == AOP_CRY) &&
2454        (AOP_TYPE(left) != AOP_CRY)) {
2455         int posbit = isLiteralBit(lit);
2456         /* left &  2^n */
2457         if(posbit){
2458             posbit--;
2459             MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2460             // bit = left & 2^n
2461             if(size) {
2462                 assert(0);
2463                 emitcode("mov","c,acc.%d",posbit&0x07);
2464             }
2465             // if(left &  2^n)
2466             else{
2467                 if (ifx) {
2468                     sprintf(buffer, "%d", posbit&0x07);
2469                     genIfxJump(ifx, buffer);
2470                 }
2471                 else {
2472                     assert(0);
2473                 }
2474                 goto release;
2475             }
2476         } else {
2477             symbol *tlbl = newiTempLabel(NULL);
2478             int sizel = AOP_SIZE(left);
2479             if(size) {
2480                 assert(0);
2481                 emitcode("setb","c");
2482             }
2483             while(sizel--){
2484                 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2485                     MOVA( aopGet(AOP(left),offset,FALSE));
2486                     // byte ==  2^n ?
2487                     if((posbit = isLiteralBit(bytelit)) != 0) {
2488                         assert(0);
2489                         emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2490                     }
2491                     else{
2492                         if(bytelit != 0x0FFL)
2493                             emitcode("and","a,%s",
2494                                      aopGet(AOP(right),offset,FALSE));
2495                         emitcode("jr","nz, %05d$",tlbl->key+100);
2496                     }
2497                 }
2498                 offset++;
2499             }
2500             // bit = left & literal
2501             if (size){
2502                 emitcode("clr","c");
2503                 emitcode("","%05d$:",tlbl->key+100);
2504             }
2505             // if(left & literal)
2506             else{
2507                 if(ifx)
2508                     jmpTrueOrFalse(ifx, tlbl);
2509                 goto release ;
2510             }
2511         }
2512         outBitC(result);
2513         goto release ;
2514     }
2515
2516     /* if left is same as result */
2517     if(sameRegs(AOP(result),AOP(left))){
2518         for(;size--; offset++) {
2519             if(AOP_TYPE(right) == AOP_LIT){
2520                 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2521                     continue;
2522                 else {
2523                     if (bytelit == 0)
2524                         aopPut(AOP(result),zero,offset);
2525                     else {
2526                         MOVA(aopGet(AOP(left),offset,FALSE));
2527                         emitcode("and","a,%s",
2528                                  aopGet(AOP(right),offset,FALSE));
2529                         emitcode("ld", "%s,a", aopGet(AOP(left),offset,FALSE));
2530                     }
2531                 }
2532
2533             } else {
2534                 if (AOP_TYPE(left) == AOP_ACC) {
2535                     assert(0);
2536                 }
2537                 else {
2538                     MOVA(aopGet(AOP(right),offset,FALSE));
2539                     emitcode("and","%s,a",
2540                              aopGet(AOP(left),offset,FALSE));
2541                 }
2542             }
2543         }
2544     } else {
2545         // left & result in different registers
2546         if(AOP_TYPE(result) == AOP_CRY){
2547             assert(0);
2548         } else {
2549             for(;(size--);offset++) {
2550                 // normal case
2551                 // result = left & right
2552                 if(AOP_TYPE(right) == AOP_LIT){
2553                     if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
2554                         aopPut(AOP(result),
2555                                aopGet(AOP(left),offset,FALSE),
2556                                offset);
2557                         continue;
2558                     } else if(bytelit == 0){
2559                         aopPut(AOP(result),zero,offset);
2560                         continue;
2561                     }
2562                 }
2563                 // faster than result <- left, anl result,right
2564                 // and better if result is SFR
2565                 if (AOP_TYPE(left) == AOP_ACC) 
2566                     emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
2567                 else {
2568                     MOVA(aopGet(AOP(right),offset,FALSE));
2569                     emitcode("and","a,%s",
2570                              aopGet(AOP(left),offset,FALSE));
2571                 }
2572                 aopPut(AOP(result),"a",offset);
2573             }
2574         }
2575
2576     }
2577
2578 release :
2579     freeAsmop(left,NULL,ic);
2580     freeAsmop(right,NULL,ic);
2581     freeAsmop(result,NULL,ic);
2582 }
2583
2584 /*-----------------------------------------------------------------*/
2585 /* genOr  - code for or                                            */
2586 /*-----------------------------------------------------------------*/
2587 static void genOr (iCode *ic, iCode *ifx)
2588 {
2589     operand *left, *right, *result;
2590     int size, offset=0;
2591     unsigned long lit = 0L;
2592
2593     aopOp((left = IC_LEFT(ic)),ic,FALSE);
2594     aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2595     aopOp((result=IC_RESULT(ic)),ic,TRUE);
2596
2597 #if 1
2598     emitcode("","; Type res[%d] = l[%d]&r[%d]",
2599              AOP_TYPE(result),
2600              AOP_TYPE(left), AOP_TYPE(right));
2601     emitcode("","; Size res[%d] = l[%d]&r[%d]",
2602              AOP_SIZE(result),
2603              AOP_SIZE(left), AOP_SIZE(right));
2604 #endif
2605
2606     /* if left is a literal & right is not then exchange them */
2607     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2608         AOP_NEEDSACC(left)) {
2609         operand *tmp = right ;
2610         right = left;
2611         left = tmp;
2612     }
2613
2614     /* if result = right then exchange them */
2615     if(sameRegs(AOP(result),AOP(right))){
2616         operand *tmp = right ;
2617         right = left;
2618         left = tmp;
2619     }
2620
2621     /* if right is bit then exchange them */
2622     if (AOP_TYPE(right) == AOP_CRY &&
2623         AOP_TYPE(left) != AOP_CRY){
2624         operand *tmp = right ;
2625         right = left;
2626         left = tmp;
2627     }
2628     if(AOP_TYPE(right) == AOP_LIT)
2629         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2630
2631     size = AOP_SIZE(result);
2632
2633     if (AOP_TYPE(left) == AOP_CRY){
2634         assert(0);
2635         goto release ;
2636     }
2637
2638     if((AOP_TYPE(right) == AOP_LIT) &&
2639        (AOP_TYPE(result) == AOP_CRY) &&
2640        (AOP_TYPE(left) != AOP_CRY)){
2641         assert(0);
2642         goto release ;
2643     }
2644
2645     /* if left is same as result */
2646     if(sameRegs(AOP(result),AOP(left))){
2647         for(;size--; offset++) {
2648             if(AOP_TYPE(right) == AOP_LIT){
2649                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2650                     continue;
2651                 else 
2652                     emitcode("or","%s,%s; 5",
2653                              aopGet(AOP(left),offset,FALSE),
2654                              aopGet(AOP(right),offset,FALSE));
2655             } else {
2656                 if (AOP_TYPE(left) == AOP_ACC) 
2657                     emitcode("or","a,%s ; 6",aopGet(AOP(right),offset,FALSE));
2658                 else {              
2659                     MOVA(aopGet(AOP(right),offset,FALSE));
2660                     emitcode("or","a,%s ; 7",
2661                              aopGet(AOP(left),offset,FALSE));
2662                     aopPut(AOP(result),"a ; 8", offset);
2663                 }
2664             }
2665         }
2666     } else {
2667         // left & result in different registers
2668         if(AOP_TYPE(result) == AOP_CRY){
2669             assert(0);
2670         } else for(;(size--);offset++){
2671             // normal case
2672             // result = left & right
2673             if(AOP_TYPE(right) == AOP_LIT){
2674                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2675                     aopPut(AOP(result),
2676                            aopGet(AOP(left),offset,FALSE),
2677                            offset);
2678                     continue;
2679                 }
2680             }
2681             // faster than result <- left, anl result,right
2682             // and better if result is SFR
2683             if (AOP_TYPE(left) == AOP_ACC) 
2684                 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2685             else {
2686                 MOVA(aopGet(AOP(right),offset,FALSE));
2687                 emitcode("or","a,%s",
2688                          aopGet(AOP(left),offset,FALSE));
2689             }
2690             aopPut(AOP(result),"a",offset);                     
2691             /* PENDING: something weird is going on here.  Add exception. */
2692             if (AOP_TYPE(result) == AOP_ACC)
2693                 break;
2694         }
2695     }
2696
2697 release :
2698     freeAsmop(left,NULL,ic);
2699     freeAsmop(right,NULL,ic);
2700     freeAsmop(result,NULL,ic);
2701 }
2702
2703 /*-----------------------------------------------------------------*/
2704 /* genXor - code for xclusive or                                   */
2705 /*-----------------------------------------------------------------*/
2706 static void genXor (iCode *ic, iCode *ifx)
2707 {
2708     operand *left, *right, *result;
2709     int size, offset=0;
2710     unsigned long lit = 0L;
2711
2712     aopOp((left = IC_LEFT(ic)),ic,FALSE);
2713     aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2714     aopOp((result=IC_RESULT(ic)),ic,TRUE);
2715
2716     /* if left is a literal & right is not then exchange them */
2717     if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2718         AOP_NEEDSACC(left)) {
2719         operand *tmp = right ;
2720         right = left;
2721         left = tmp;
2722     }
2723
2724     /* if result = right then exchange them */
2725     if(sameRegs(AOP(result),AOP(right))){
2726         operand *tmp = right ;
2727         right = left;
2728         left = tmp;
2729     }
2730
2731     /* if right is bit then exchange them */
2732     if (AOP_TYPE(right) == AOP_CRY &&
2733         AOP_TYPE(left) != AOP_CRY){
2734         operand *tmp = right ;
2735         right = left;
2736         left = tmp;
2737     }
2738     if(AOP_TYPE(right) == AOP_LIT)
2739         lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2740
2741     size = AOP_SIZE(result);
2742
2743     if (AOP_TYPE(left) == AOP_CRY){
2744         assert(0);
2745         goto release ;
2746     }
2747
2748     if((AOP_TYPE(right) == AOP_LIT) &&
2749        (AOP_TYPE(result) == AOP_CRY) &&
2750        (AOP_TYPE(left) != AOP_CRY)){
2751         assert(0);
2752         goto release ;
2753     }
2754
2755     /* if left is same as result */
2756     if(sameRegs(AOP(result),AOP(left))){
2757         for(;size--; offset++) {
2758             if(AOP_TYPE(right) == AOP_LIT){
2759                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2760                     continue;
2761                 else {
2762                     MOVA(aopGet(AOP(right),offset,FALSE));
2763                     emitcode("xor","a,%s",
2764                              aopGet(AOP(left),offset,FALSE));
2765                     aopPut(AOP(result),"a",0);
2766                 }
2767             } else {
2768                 if (AOP_TYPE(left) == AOP_ACC) 
2769                     emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
2770                 else {              
2771                     MOVA(aopGet(AOP(right),offset,FALSE));
2772                     emitcode("xor","a,%s",
2773                              aopGet(AOP(left),offset,FALSE));
2774                     aopPut(AOP(result),"a",0);
2775                 }
2776             }
2777         }
2778     } else {
2779         // left & result in different registers
2780         if(AOP_TYPE(result) == AOP_CRY){
2781             assert(0);
2782         } else for(;(size--);offset++){
2783             // normal case
2784             // result = left & right
2785             if(AOP_TYPE(right) == AOP_LIT){
2786                 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2787                     aopPut(AOP(result),
2788                            aopGet(AOP(left),offset,FALSE),
2789                            offset);
2790                     continue;
2791                 }
2792             }
2793             // faster than result <- left, anl result,right
2794             // and better if result is SFR
2795             if (AOP_TYPE(left) == AOP_ACC) 
2796                 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
2797             else {
2798                 MOVA(aopGet(AOP(right),offset,FALSE));
2799                 emitcode("xor","a,%s",
2800                          aopGet(AOP(left),offset,FALSE));
2801                 aopPut(AOP(result),"a",0);
2802             }
2803             aopPut(AOP(result),"a",offset);                     
2804         }
2805     }
2806
2807 release :
2808     freeAsmop(left,NULL,ic);
2809     freeAsmop(right,NULL,ic);
2810     freeAsmop(result,NULL,ic);
2811 }
2812
2813 /*-----------------------------------------------------------------*/
2814 /* genInline - write the inline code out                           */
2815 /*-----------------------------------------------------------------*/
2816 static void genInline (iCode *ic)
2817 {
2818     char buffer[MAX_INLINEASM];
2819     char *bp = buffer;
2820     char *bp1= buffer;
2821     
2822     inLine += (!options.asmpeep);
2823     strcpy(buffer,IC_INLINE(ic));
2824
2825     /* emit each line as a code */
2826     while (*bp) {
2827         if (*bp == '\n') {
2828             *bp++ = '\0';
2829             emitcode(bp1,"");
2830             bp1 = bp;
2831         } else {
2832             if (*bp == ':') {
2833                 bp++;
2834                 *bp = '\0';
2835                 bp++;
2836                 emitcode(bp1,"");
2837                 bp1 = bp;
2838             } else
2839                 bp++;
2840         }
2841     }
2842     if (bp1 != bp)
2843         emitcode(bp1,"");
2844     /*     emitcode("",buffer); */
2845     inLine -= (!options.asmpeep);
2846 }
2847
2848 /*-----------------------------------------------------------------*/
2849 /* genRRC - rotate right with carry                                */
2850 /*-----------------------------------------------------------------*/
2851 static void genRRC (iCode *ic)
2852 {
2853     assert(0);
2854 }
2855
2856 /*-----------------------------------------------------------------*/
2857 /* genRLC - generate code for rotate left with carry               */
2858 /*-----------------------------------------------------------------*/
2859 static void genRLC (iCode *ic)
2860 {    
2861     assert(0);
2862 }
2863
2864 /*-----------------------------------------------------------------*/
2865 /* shiftR2Left2Result - shift right two bytes from left to result  */
2866 /*-----------------------------------------------------------------*/
2867 static void shiftR2Left2Result (operand *left, int offl,
2868                                 operand *result, int offr,
2869                                 int shCount, int sign)
2870 {
2871     if(sameRegs(AOP(result), AOP(left)) &&
2872        ((offl + MSB16) == offr)){
2873         assert(0);
2874     } else {
2875         movLeft2Result(left, offl, result, offr, 0);
2876         movLeft2Result(left, offl+1, result, offr+1, 0);
2877     }
2878
2879     if (sign) {
2880         assert(0);
2881     }
2882     else {
2883         /*      if (AOP(result)->type == AOP_REG) {*/
2884             int size = 2;
2885             int offset = 0;
2886             symbol *tlbl , *tlbl1;
2887             char *l;
2888
2889             /* Left is already in result - so now do the shift */
2890             if (shCount>1) {
2891                 emitcode("ld","a,#%u+1", shCount);
2892                 tlbl = newiTempLabel(NULL);
2893                 tlbl1 = newiTempLabel(NULL);
2894                 emitcode(_shortJP, LABEL_STR ,tlbl1->key+100); 
2895                 emitcode("", LABEL_STR ":",tlbl->key+100);    
2896             }
2897
2898             emitcode("or", "a,a");
2899             offset = size;
2900             while (size--) {
2901                 l = aopGet(AOP(result), --offset, FALSE);
2902                 emitcode("rr","%s", l);         
2903             }
2904             if (shCount>1) {
2905                 emitcode("", LABEL_STR ":",tlbl1->key+100);
2906                 emitcode("dec", "a");
2907                 emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
2908             }
2909     }
2910 }
2911
2912 /*-----------------------------------------------------------------*/
2913 /* shiftL2Left2Result - shift left two bytes from left to result   */
2914 /*-----------------------------------------------------------------*/
2915 static void shiftL2Left2Result (operand *left, int offl,
2916                                 operand *result, int offr, int shCount)
2917 {
2918     if(sameRegs(AOP(result), AOP(left)) &&
2919        ((offl + MSB16) == offr)){
2920         assert(0);
2921     } else {
2922         /* Copy left into result */
2923         movLeft2Result(left, offl, result, offr, 0);
2924         movLeft2Result(left, offl+1, result, offr+1, 0);
2925     }
2926     /* PENDING: for now just see if it'll work. */
2927     /*if (AOP(result)->type == AOP_REG) { */
2928     {
2929         int size = 2;
2930         int offset = 0;
2931         symbol *tlbl , *tlbl1;
2932         char *l;
2933
2934         /* Left is already in result - so now do the shift */
2935         if (shCount>1) {
2936             emitcode("ld","a,#%u+1", shCount);
2937             tlbl = newiTempLabel(NULL);
2938             tlbl1 = newiTempLabel(NULL);
2939             emitcode(_shortJP, LABEL_STR ,tlbl1->key+100); 
2940             emitcode("", LABEL_STR ":",tlbl->key+100);    
2941         }
2942
2943         emitcode("or", "a,a");
2944         while (size--) {
2945             l = aopGet(AOP(result),offset++,FALSE);
2946             emitcode("rl","%s", l);         
2947         }
2948         if (shCount>1) {
2949             emitcode("", LABEL_STR ":",tlbl1->key+100);
2950             emitcode("dec", "a");
2951             emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
2952         }
2953     }
2954 }
2955
2956 /*-----------------------------------------------------------------*/
2957 /* AccRol - rotate left accumulator by known count                 */
2958 /*-----------------------------------------------------------------*/
2959 static void AccRol (int shCount)
2960 {
2961     shCount &= 0x0007;              // shCount : 0..7
2962     switch(shCount){
2963         case 0 :
2964             break;
2965         case 1 :
2966             emitcode("rl","a");
2967             break;
2968         case 2 :
2969             emitcode("rl","a");
2970             emitcode("rl","a");
2971             break;
2972         case 3 :
2973             emitcode("rl","a");
2974             emitcode("rl","a");
2975             emitcode("rl","a");
2976             break;
2977         case 4 :
2978             emitcode("rl","a");
2979             emitcode("rl","a");
2980             emitcode("rl","a");
2981             emitcode("rl","a");
2982             break;
2983         case 5 :
2984             emitcode("rr","a");
2985             emitcode("rr","a");
2986             emitcode("rr","a");
2987             break;
2988         case 6 :
2989             emitcode("rr","a");
2990             emitcode("rr","a");
2991             break;
2992         case 7 :
2993             emitcode("rr","a");
2994             break;
2995     }
2996 }
2997
2998 /*-----------------------------------------------------------------*/
2999 /* AccLsh - left shift accumulator by known count                  */
3000 /*-----------------------------------------------------------------*/
3001 static void AccLsh (int shCount)
3002 {
3003     if(shCount != 0){
3004         if(shCount == 1)
3005             emitcode("add","a,a");
3006         else 
3007             if(shCount == 2) {
3008             emitcode("add","a,a");
3009             emitcode("add","a,a");
3010         } else {
3011             /* rotate left accumulator */
3012             AccRol(shCount);
3013             /* and kill the lower order bits */
3014             emitcode("and","a,#0x%02x", SLMask[shCount]);
3015         }
3016     }
3017 }
3018
3019 /*-----------------------------------------------------------------*/
3020 /* shiftL1Left2Result - shift left one byte from left to result    */
3021 /*-----------------------------------------------------------------*/
3022 static void shiftL1Left2Result (operand *left, int offl,
3023                                 operand *result, int offr, int shCount)
3024 {
3025     char *l;
3026     l = aopGet(AOP(left),offl,FALSE);
3027     MOVA(l);
3028     /* shift left accumulator */
3029     AccLsh(shCount);
3030     aopPut(AOP(result),"a",offr);
3031 }
3032
3033
3034 /*-----------------------------------------------------------------*/
3035 /* genlshTwo - left shift two bytes by known amount != 0           */
3036 /*-----------------------------------------------------------------*/
3037 static void genlshTwo (operand *result,operand *left, int shCount)
3038 {
3039     int size = AOP_SIZE(result);
3040
3041     assert(size==2);
3042
3043     /* if shCount >= 8 */
3044     if (shCount >= 8) {
3045         shCount -= 8 ;
3046
3047         if (size > 1){
3048             if (shCount) {
3049                 movLeft2Result(left, LSB, result, MSB16, 0);
3050                 aopPut(AOP(result),zero, 0);   
3051                 shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
3052             }
3053             else {
3054                 movLeft2Result(left, LSB, result, MSB16, 0);
3055                 aopPut(AOP(result),zero, 0);   
3056             }
3057         }
3058         aopPut(AOP(result),zero,LSB);   
3059     }
3060     /*  1 <= shCount <= 7 */
3061     else {  
3062         if(size == 1) {
3063             assert(0);
3064         }
3065         else {
3066             shiftL2Left2Result(left, LSB, result, LSB, shCount);
3067         }
3068     }
3069 }
3070
3071 /*-----------------------------------------------------------------*/
3072 /* genlshOne - left shift a one byte quantity by known count       */
3073 /*-----------------------------------------------------------------*/
3074 static void genlshOne (operand *result, operand *left, int shCount)
3075 {       
3076     shiftL1Left2Result(left, LSB, result, LSB, shCount);
3077 }
3078
3079 /*-----------------------------------------------------------------*/
3080 /* genLeftShiftLiteral - left shifting by known count              */
3081 /*-----------------------------------------------------------------*/
3082 static void genLeftShiftLiteral (operand *left,
3083                                  operand *right,
3084                                  operand *result,
3085                                  iCode *ic)
3086 {    
3087     int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3088     int size;
3089
3090     freeAsmop(right,NULL,ic);
3091
3092     aopOp(left,ic,FALSE);
3093     aopOp(result,ic,FALSE);
3094
3095     size = getSize(operandType(result));
3096
3097 #if VIEW_SIZE
3098     emitcode("; shift left ","result %d, left %d",size,
3099              AOP_SIZE(left));
3100 #endif
3101
3102     /* I suppose that the left size >= result size */
3103     if (shCount == 0) {
3104         assert(0);
3105     }
3106
3107     else if(shCount >= (size * 8))
3108         while(size--)
3109             aopPut(AOP(result),zero,size);
3110     else{
3111         switch (size) {
3112         case 1:
3113             genlshOne (result,left,shCount);
3114             break;
3115         case 2:
3116             genlshTwo (result,left,shCount);
3117             break;
3118         case 4:
3119             assert(0);
3120             break;
3121         default:
3122             assert(0);
3123         }
3124     }
3125     freeAsmop(left,NULL,ic);
3126     freeAsmop(result,NULL,ic);
3127 }
3128
3129 /*-----------------------------------------------------------------*/
3130 /* genLeftShift - generates code for left shifting                 */
3131 /*-----------------------------------------------------------------*/
3132 static void genLeftShift (iCode *ic)
3133 {
3134     int size, offset;
3135     char *l;
3136     symbol *tlbl , *tlbl1;
3137     operand *left,*right, *result;
3138
3139     right = IC_RIGHT(ic);
3140     left  = IC_LEFT(ic);
3141     result = IC_RESULT(ic);
3142
3143     aopOp(right,ic,FALSE);
3144
3145     /* if the shift count is known then do it 
3146     as efficiently as possible */
3147     if (AOP_TYPE(right) == AOP_LIT) {
3148         genLeftShiftLiteral (left,right,result,ic);
3149         return ;
3150     }
3151
3152     /* shift count is unknown then we have to form a loop get the loop
3153        count in B : Note: we take only the lower order byte since
3154        shifting more that 32 bits make no sense anyway, ( the largest
3155        size of an object can be only 32 bits ) */
3156     emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
3157     emitcode("inc","a");
3158     freeAsmop (right,NULL,ic);
3159     aopOp(left,ic,FALSE);
3160     aopOp(result,ic,FALSE);
3161
3162     /* now move the left to the result if they are not the
3163        same */
3164 #if 1
3165     if (!sameRegs(AOP(left),AOP(result))) {
3166
3167         size = AOP_SIZE(result);
3168         offset = 0;
3169         while (size--) {
3170             l = aopGet(AOP(left),offset,FALSE);
3171             aopPut(AOP(result),l,offset);
3172             offset++;
3173         }
3174     }
3175 #else
3176     size = AOP_SIZE(result);
3177     offset = 0;
3178     while (size--) {
3179         l = aopGet(AOP(left),offset,FALSE);
3180         aopPut(AOP(result),l,offset);
3181         offset++;
3182     }
3183 #endif
3184
3185
3186     tlbl = newiTempLabel(NULL);
3187     size = AOP_SIZE(result);
3188     offset = 0 ;   
3189     tlbl1 = newiTempLabel(NULL);
3190
3191     emitcode(_shortJP, LABEL_STR ,tlbl1->key+100); 
3192     emitcode("", LABEL_STR ":",tlbl->key+100);    
3193     l = aopGet(AOP(result),offset,FALSE);
3194     emitcode("or", "a,a");
3195     while (size--) {
3196         l = aopGet(AOP(result),offset++,FALSE);
3197         emitcode("rl","%s", l);         
3198     }
3199     emitcode("", LABEL_STR ":",tlbl1->key+100);
3200     emitcode("dec", "a");
3201     emitcode(_shortJP,"nz," LABEL_STR ,tlbl->key+100);
3202
3203     freeAsmop(left,NULL,ic);
3204     freeAsmop(result,NULL,ic);
3205 }
3206
3207 /* genlshTwo - left shift two bytes by known amount != 0           */
3208 /*-----------------------------------------------------------------*/
3209 static void genrshOne (operand *result,operand *left, int shCount)
3210 {
3211     /* Errk */
3212     int size = AOP_SIZE(result);
3213     char *l;
3214
3215     assert(size==1);
3216     assert(shCount<8);
3217
3218     l = aopGet(AOP(left),0,FALSE);
3219     if (AOP(result)->type == AOP_REG) {
3220         aopPut(AOP(result), l, 0);
3221         l = aopGet(AOP(result), 0, FALSE);
3222         while (shCount--) 
3223             emitcode("srl", "%s", l);
3224     }
3225     else {
3226         MOVA(l);
3227         while (shCount--) {
3228             emitcode("srl", "a");
3229         }
3230         aopPut(AOP(result),"a",0);
3231     }
3232 }
3233
3234 /*-----------------------------------------------------------------*/
3235 /* AccRsh - right shift accumulator by known count                 */
3236 /*-----------------------------------------------------------------*/
3237 static void AccRsh (int shCount)
3238 {
3239     if(shCount != 0){
3240         if(shCount == 1){
3241             CLRC;
3242             emitcode("rr","a");
3243         } else {
3244             /* rotate right accumulator */
3245             AccRol(8 - shCount);
3246             /* and kill the higher order bits */
3247             emitcode("and","a,#0x%02x", SRMask[shCount]);
3248         }
3249     }
3250 }
3251
3252 /*-----------------------------------------------------------------*/
3253 /* shiftR1Left2Result - shift right one byte from left to result   */
3254 /*-----------------------------------------------------------------*/
3255 static void shiftR1Left2Result (operand *left, int offl,
3256                                 operand *result, int offr,
3257                                 int shCount, int sign)
3258 {
3259     MOVA(aopGet(AOP(left),offl,FALSE));
3260     if (sign) {
3261         assert(0);
3262     }
3263     else {
3264         AccRsh(shCount);
3265     }
3266     aopPut(AOP(result),"a",offr);
3267 }
3268
3269 /*-----------------------------------------------------------------*/
3270 /* genrshTwo - right shift two bytes by known amount != 0          */
3271 /*-----------------------------------------------------------------*/
3272 static void genrshTwo (operand *result,operand *left,
3273                        int shCount, int sign)
3274 {
3275     /* if shCount >= 8 */
3276     if (shCount >= 8) {
3277         shCount -= 8 ;
3278         if (shCount) {
3279             assert(0);
3280             shiftR1Left2Result(left, MSB16, result, LSB,
3281                                shCount, sign);
3282         }
3283         else {
3284             movLeft2Result(left, MSB16, result, LSB, sign);
3285             aopPut(AOP(result),zero,1);
3286         }
3287     }
3288     /*  1 <= shCount <= 7 */
3289     else {
3290         shiftR2Left2Result(left, LSB, result, LSB, shCount, sign); 
3291     }
3292 }
3293
3294 /*-----------------------------------------------------------------*/
3295 /* genRightShiftLiteral - left shifting by known count              */
3296 /*-----------------------------------------------------------------*/
3297 static void genRightShiftLiteral (operand *left,
3298                                  operand *right,
3299                                  operand *result,
3300                                  iCode *ic)
3301 {    
3302     int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
3303     int size;
3304
3305     freeAsmop(right,NULL,ic);
3306
3307     aopOp(left,ic,FALSE);
3308     aopOp(result,ic,FALSE);
3309
3310     size = getSize(operandType(result));
3311
3312     emitcode("; shift right ","result %d, left %d",size,
3313              AOP_SIZE(left));
3314
3315     /* I suppose that the left size >= result size */
3316     if (shCount == 0) {
3317         assert(0);
3318     }
3319
3320     else if(shCount >= (size * 8))
3321         while(size--)
3322             aopPut(AOP(result),zero,size);
3323     else{
3324         switch (size) {
3325         case 1:
3326             genrshOne(result, left, shCount);
3327             break;
3328         case 2:
3329             /* PENDING: sign support */
3330             genrshTwo(result, left, shCount, FALSE);
3331             break;
3332         case 4:
3333             assert(0);
3334             break;
3335         default:
3336             assert(0);
3337         }
3338     }
3339     freeAsmop(left,NULL,ic);
3340     freeAsmop(result,NULL,ic);
3341 }
3342
3343 /*-----------------------------------------------------------------*/
3344 /* genRightShift - generate code for right shifting                */
3345 /*-----------------------------------------------------------------*/
3346 static void genRightShift (iCode *ic)
3347 {
3348     operand *left,*right, *result;
3349
3350     right = IC_RIGHT(ic);
3351     left  = IC_LEFT(ic);
3352     result = IC_RESULT(ic);
3353
3354     aopOp(right,ic,FALSE);
3355
3356     /* if the shift count is known then do it 
3357     as efficiently as possible */
3358     if (AOP_TYPE(right) == AOP_LIT) {
3359         genRightShiftLiteral (left,right,result,ic);
3360         return ;
3361     }
3362     else {
3363         assert(0);
3364     }
3365 }
3366
3367 /*-----------------------------------------------------------------*/
3368 /* genGenPointerGet - gget value from generic pointer space        */
3369 /*-----------------------------------------------------------------*/
3370 static void genGenPointerGet (operand *left,
3371                               operand *result, iCode *ic)
3372 {
3373     int size, offset ;
3374     link *retype = getSpec(operandType(result));
3375     const char *ptr = "hl";
3376
3377     if (IS_GB)
3378         ptr = "de";
3379
3380     aopOp(left,ic,FALSE);
3381     aopOp(result,ic,FALSE);
3382
3383     if (isPair(AOP(left)) && (AOP_SIZE(result)==1)) {
3384         /* Just do it */
3385         emitcode("ld", "a,(%s)", getPairName(AOP(left)));
3386         aopPut(AOP(result),"a", 0);
3387         freeAsmop(left,NULL,ic);
3388         goto release;
3389     }
3390
3391     /* For now we always load into IY */
3392     /* if this is remateriazable */
3393     if (AOP_TYPE(left) == AOP_IMMD)
3394         emitcode("ld","%s,%s", ptr, aopGet(AOP(left),0,TRUE));
3395     else { /* we need to get it byte by byte */
3396         if (IS_GB) {
3397             emitcode("ld", "e,%s", aopGet(AOP(left), 0, FALSE));
3398             emitcode("ld", "d,%s", aopGet(AOP(left), 1, FALSE));
3399         }
3400         else
3401             fetchHL(AOP(left));
3402     }
3403     /* so iy now contains the address */
3404     freeAsmop(left,NULL,ic);
3405
3406     /* if bit then unpack */
3407     if (IS_BITVAR(retype)) {
3408         assert(0);
3409     }
3410     else {
3411         size = AOP_SIZE(result);
3412         offset = 0 ;
3413
3414         while (size--) {
3415             /* PENDING: make this better */
3416             if (!IS_GB && AOP(result)->type == AOP_REG) {
3417                 aopPut(AOP(result),"(hl)",offset++);
3418             }
3419             else {
3420                 emitcode("ld", "a,(%s)", ptr, offset);
3421                 aopPut(AOP(result),"a",offset++);
3422             }
3423             if (size) {
3424                 emitcode("inc", "%s", ptr);
3425             }
3426         }
3427     }
3428
3429  release:
3430     freeAsmop(result,NULL,ic);
3431 }
3432
3433 /*-----------------------------------------------------------------*/
3434 /* genPointerGet - generate code for pointer get                   */
3435 /*-----------------------------------------------------------------*/
3436 static void genPointerGet (iCode *ic)
3437 {
3438     operand *left, *result ;
3439     link *type, *etype;
3440
3441     left = IC_LEFT(ic);
3442     result = IC_RESULT(ic) ;
3443
3444     /* depending on the type of pointer we need to
3445     move it to the correct pointer register */
3446     type = operandType(left);
3447     etype = getSpec(type);
3448
3449     genGenPointerGet (left,result,ic);
3450 }
3451
3452 bool isRegOrLit(asmop *aop)
3453 {
3454     if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3455         return TRUE;
3456     return FALSE;
3457 }
3458
3459 /*-----------------------------------------------------------------*/
3460 /* genGenPointerSet - stores the value into a pointer location        */
3461 /*-----------------------------------------------------------------*/
3462 static void genGenPointerSet (operand *right,
3463                               operand *result, iCode *ic)
3464 {    
3465     int size, offset ;
3466     link *retype = getSpec(operandType(right));
3467     const char *ptr = "hl";
3468
3469     aopOp(result,ic,FALSE);
3470     aopOp(right,ic,FALSE);
3471
3472     if (IS_GB)
3473         ptr = "de";
3474
3475     /* Handle the exceptions first */
3476     if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3477         /* Just do it */
3478         char *l = aopGet(AOP(right), 0, FALSE);
3479         MOVA(l);
3480         emitcode("ld", "(%s),a", getPairName(AOP(result)));
3481         freeAsmop(result,NULL,ic);
3482         goto release;
3483     }
3484         
3485     /* if the operand is already in dptr 
3486        then we do nothing else we move the value to dptr */
3487     if (AOP_TYPE(result) != AOP_STR) {
3488         /* if this is remateriazable */
3489         if (AOP_TYPE(result) == AOP_IMMD) {
3490             emitcode("", "; Error 2");
3491             emitcode("ld", "%s,%s", ptr, aopGet(AOP(result), 0, TRUE));
3492         }
3493         else { /* we need to get it byte by byte */
3494             if (IS_GB) {
3495                 emitcode("ld", "e,%s", aopGet(AOP(result), 0, TRUE));
3496                 emitcode("ld", "d,%s", aopGet(AOP(result), 1, TRUE));
3497             }
3498             else {
3499                 /* PENDING: do this better */
3500                 fetchHL(AOP(result));
3501             }
3502         }
3503     }
3504     /* so hl know contains the address */
3505     freeAsmop(result,NULL,ic);
3506
3507     /* if bit then unpack */
3508     if (IS_BITVAR(retype)) {
3509         assert(0);
3510     }
3511     else {
3512         size = AOP_SIZE(right);
3513         offset = 0 ;
3514
3515         while (size--) {
3516             char *l = aopGet(AOP(right),offset,FALSE);
3517             if (isRegOrLit(AOP(right)) && !IS_GB) {
3518                 emitcode("ld", "(%s),%s", ptr, l);
3519             }
3520             else {
3521                 MOVA(l);
3522                 emitcode("ld", "(%s),a", ptr, offset);
3523             }
3524             if (size) {
3525                 emitcode("inc", ptr);
3526             }
3527             offset++;
3528         }
3529     }
3530     release:
3531     freeAsmop(right,NULL,ic);
3532 }
3533
3534 /*-----------------------------------------------------------------*/
3535 /* genPointerSet - stores the value into a pointer location        */
3536 /*-----------------------------------------------------------------*/
3537 static void genPointerSet (iCode *ic)
3538 {    
3539     operand *right, *result ;
3540     link *type, *etype;
3541
3542     right = IC_RIGHT(ic);
3543     result = IC_RESULT(ic) ;
3544
3545     /* depending on the type of pointer we need to
3546     move it to the correct pointer register */
3547     type = operandType(result);
3548     etype = getSpec(type);
3549     
3550     genGenPointerSet (right,result,ic);
3551 }
3552
3553 /*-----------------------------------------------------------------*/
3554 /* genIfx - generate code for Ifx statement                        */
3555 /*-----------------------------------------------------------------*/
3556 static void genIfx (iCode *ic, iCode *popIc)
3557 {
3558     operand *cond = IC_COND(ic);
3559     int isbit =0;
3560
3561     aopOp(cond,ic,FALSE);
3562
3563     /* get the value into acc */
3564     if (AOP_TYPE(cond) != AOP_CRY)
3565         toBoolean(cond);
3566     else
3567         isbit = 1;
3568     /* the result is now in the accumulator */
3569     freeAsmop(cond,NULL,ic);
3570
3571     /* if there was something to be popped then do it */
3572     if (popIc)
3573         genIpop(popIc);
3574
3575     /* if the condition is  a bit variable */
3576     if (isbit && IS_ITEMP(cond) && 
3577         SPIL_LOC(cond))
3578         genIfxJump(ic,SPIL_LOC(cond)->rname);
3579     else
3580         if (isbit && !IS_ITEMP(cond))
3581             genIfxJump(ic,OP_SYMBOL(cond)->rname);
3582         else
3583             genIfxJump(ic,"a");
3584
3585     ic->generated = 1;
3586 }
3587
3588 /*-----------------------------------------------------------------*/
3589 /* genAddrOf - generates code for address of                       */
3590 /*-----------------------------------------------------------------*/
3591 static void genAddrOf (iCode *ic)
3592 {
3593     symbol *sym = OP_SYMBOL(IC_LEFT(ic));
3594
3595     aopOp(IC_RESULT(ic),ic,FALSE);
3596
3597     /* if the operand is on the stack then we 
3598     need to get the stack offset of this
3599     variable */
3600     if (sym->onStack) {
3601         /* if it has an offset  then we need to compute it */
3602         if (IS_GB) {
3603             emitcode("lda", "hl,%d+%d+%d(sp)", sym->stack, _pushed, _spoffset);
3604             emitcode("ld", "d,h");
3605             emitcode("ld", "e,l");
3606             aopPut(AOP(IC_RESULT(ic)), "e", 0);
3607             aopPut(AOP(IC_RESULT(ic)), "d", 1);
3608             goto end;
3609         }
3610         else {
3611             emitcode("push", "de");
3612             emitcode("push", "ix");
3613             emitcode("pop", "hl");
3614             emitcode("ld", "de,#%d", sym->stack);
3615             emitcode("add", "hl,de");
3616             emitcode("pop", "de");
3617         }
3618     }
3619     else {
3620         emitcode("ld", "hl,#%s", sym->rname);
3621     }
3622     aopPut(AOP(IC_RESULT(ic)), "l", 0);
3623     aopPut(AOP(IC_RESULT(ic)), "h", 1);
3624 end:
3625     freeAsmop(IC_RESULT(ic),NULL,ic);
3626 }
3627
3628 /*-----------------------------------------------------------------*/
3629 /* genAssign - generate code for assignment                        */
3630 /*-----------------------------------------------------------------*/
3631 static void genAssign (iCode *ic)
3632 {
3633     operand *result, *right;
3634     int size, offset ;
3635     unsigned long lit = 0L;
3636
3637     result = IC_RESULT(ic);
3638     right  = IC_RIGHT(ic) ;
3639
3640 #if 1
3641     /* Dont bother assigning if they are the same */
3642     if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
3643         emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
3644         return;
3645     }
3646 #endif
3647
3648     aopOp(right,ic,FALSE);
3649     aopOp(result,ic,TRUE);
3650
3651     /* if they are the same registers */
3652     if (sameRegs(AOP(right),AOP(result))) {
3653         emitcode("", "; (registers are the same)");
3654         goto release;
3655     }
3656
3657     /* if the result is a bit */
3658     if (AOP_TYPE(result) == AOP_CRY) {
3659         assert(0);
3660     }
3661
3662     /* general case */
3663     size = AOP_SIZE(result);
3664     offset = 0;
3665
3666     if(AOP_TYPE(right) == AOP_LIT)
3667         lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
3668     if((size > 1) &&
3669        (AOP_TYPE(result) != AOP_REG) &&
3670        (AOP_TYPE(right) == AOP_LIT) &&
3671        !IS_FLOAT(operandType(right)) &&
3672        (lit < 256L)) {
3673         bool fXored = FALSE;
3674         offset = 0;
3675         /* Work from the top down.
3676            Done this way so that we can use the cached copy of 0
3677            in A for a fast clear */
3678         while (size--) {
3679             if((unsigned int)((lit >> (offset*8)) & 0x0FFL)== 0) {
3680                 if (!fXored && size>1) {
3681                     emitcode("xor", "a,a");
3682                     fXored = TRUE;
3683                 }
3684                 if (fXored) {
3685                     aopPut(AOP(result),"a",offset);
3686                 }
3687                 else {
3688                     aopPut(AOP(result), "#0", offset);
3689                 }
3690             }
3691             else
3692                 aopPut(AOP(result),
3693                        aopGet(AOP(right),offset,FALSE),
3694                        offset);
3695             offset++;
3696         }
3697     }
3698     else if (size == 2 && requiresHL(AOP(right)) && requiresHL(AOP(result))) {
3699         /* Special case.  Load into a and d, then load out. */
3700         MOVA(aopGet(AOP(right), 0, FALSE));
3701         emitcode("ld", "e,%s", aopGet(AOP(right), 1, FALSE));
3702         aopPut(AOP(result), "a", 0);
3703         aopPut(AOP(result), "e", 1);
3704     } else {
3705         while (size--) {
3706             aopPut(AOP(result),
3707                    aopGet(AOP(right),offset,FALSE),
3708                    offset);
3709             offset++;
3710         }
3711     }
3712     
3713 release:
3714     freeAsmop(right,NULL,ic);
3715     freeAsmop(result,NULL,ic);
3716 }   
3717
3718 /*-----------------------------------------------------------------*/
3719 /* genJumpTab - genrates code for jump table                       */
3720 /*-----------------------------------------------------------------*/
3721 static void genJumpTab (iCode *ic)
3722 {
3723     symbol *jtab;
3724     char *l;
3725
3726     aopOp(IC_JTCOND(ic),ic,FALSE);
3727     /* get the condition into accumulator */
3728     l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
3729     MOVA(l);
3730     if (!IS_GB)
3731         emitcode("push", "de");
3732     emitcode("ld", "e,%s", l);
3733     emitcode("ld", "d,#0");
3734     jtab = newiTempLabel(NULL);
3735     emitcode("ld", "hl,#" LABEL_STR, jtab->key+100);
3736     emitcode("add", "hl,de");
3737     emitcode("add", "hl,de");
3738     emitcode("add", "hl,de");
3739     freeAsmop(IC_JTCOND(ic),NULL,ic);
3740     if (!IS_GB)
3741         emitcode("pop", "de");
3742     emitcode("jp", "(hl)");
3743     emitcode("","%05d$:",jtab->key+100);
3744     /* now generate the jump labels */
3745     for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
3746          jtab = setNextItem(IC_JTLABELS(ic)))
3747         emitcode("jp", LABEL_STR, jtab->key+100);
3748 }
3749
3750 /*-----------------------------------------------------------------*/
3751 /* genCast - gen code for casting                                  */
3752 /*-----------------------------------------------------------------*/
3753 static void genCast (iCode *ic)
3754 {
3755     operand *result = IC_RESULT(ic);
3756     link *ctype = operandType(IC_LEFT(ic));
3757     operand *right = IC_RIGHT(ic);
3758     int size, offset ;
3759
3760     /* if they are equivalent then do nothing */
3761     if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
3762         return ;
3763
3764     aopOp(right,ic,FALSE) ;
3765     aopOp(result,ic,FALSE);
3766
3767     /* if the result is a bit */
3768     if (AOP_TYPE(result) == AOP_CRY) {
3769         assert(0);
3770     }
3771
3772     /* if they are the same size : or less */
3773     if (AOP_SIZE(result) <= AOP_SIZE(right)) {
3774
3775         /* if they are in the same place */
3776         if (sameRegs(AOP(right),AOP(result)))
3777             goto release;
3778
3779         /* if they in different places then copy */
3780         size = AOP_SIZE(result);
3781         offset = 0 ;
3782         while (size--) {
3783             aopPut(AOP(result),
3784                    aopGet(AOP(right),offset,FALSE),
3785                    offset);
3786             offset++;
3787         }
3788         goto release;
3789     }
3790
3791     /* PENDING: should be OK. */
3792 #if 0
3793     /* if the result is of type pointer */
3794     if (IS_PTR(ctype)) {
3795         assert(0);
3796     }
3797 #endif
3798     
3799     /* so we now know that the size of destination is greater
3800     than the size of the source */
3801     /* we move to result for the size of source */
3802     size = AOP_SIZE(right);
3803     offset = 0 ;
3804     while (size--) {
3805         aopPut(AOP(result),
3806                aopGet(AOP(right),offset,FALSE),
3807                offset);
3808         offset++;
3809     }
3810
3811     /* now depending on the sign of the destination */
3812     size = AOP_SIZE(result) - AOP_SIZE(right);
3813     /* Unsigned or not an integral type - right fill with zeros */
3814     if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
3815         while (size--)
3816             aopPut(AOP(result),zero,offset++);
3817     } else {
3818         /* we need to extend the sign :{ */
3819         char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
3820                          FALSE);
3821         MOVA(l);
3822         emitcode("", "; genCast: sign extend untested.");
3823         emitcode("rla", "");
3824         emitcode("sbc", "a,a");
3825         while (size--)
3826             aopPut(AOP(result),"a",offset++);   
3827     }
3828
3829 release:
3830     freeAsmop(right, NULL, ic);
3831     freeAsmop(result, NULL, ic);
3832 }
3833
3834 /*-----------------------------------------------------------------*/
3835 /* genReceive - generate code for a receive iCode                  */
3836 /*-----------------------------------------------------------------*/
3837 static void genReceive (iCode *ic)
3838 {    
3839     if (isOperandInFarSpace(IC_RESULT(ic)) && 
3840         ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
3841           IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
3842         assert(0);
3843     } else {
3844         accInUse++;
3845         aopOp(IC_RESULT(ic),ic,FALSE);  
3846         accInUse--;
3847         assignResultValue(IC_RESULT(ic));       
3848     }
3849
3850     freeAsmop(IC_RESULT(ic),NULL,ic);
3851 }
3852
3853 /*-----------------------------------------------------------------*/
3854 /* genZ80Code - generate code for Z80 based controllers            */
3855 /*-----------------------------------------------------------------*/
3856 void genZ80Code (iCode *lic)
3857 {
3858     iCode *ic;
3859     int cln = 0;
3860
3861     /* HACK */
3862     if (IS_GB) {
3863         _fReturn = _gbz80_return;
3864         _fTmp = _gbz80_return;
3865         _shortJP = "jr";
3866     }
3867     else {
3868         _fReturn = _z80_return;
3869         _fTmp = _z80_return;
3870         _shortJP = "jp";
3871     }
3872
3873     lineHead = lineCurr = NULL;
3874
3875     /* if debug information required */
3876     if (options.debug && currFunc) { 
3877         cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
3878         debugLine = 1;
3879         if (IS_STATIC(currFunc->etype))
3880             emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name); 
3881         else
3882             emitcode("","G$%s$0$0 ==.",currFunc->name);
3883         debugLine = 0;
3884     }
3885     /* stack pointer name */
3886     spname = "sp";
3887     
3888  
3889     for (ic = lic ; ic ; ic = ic->next ) {
3890         
3891         if ( cln != ic->lineno ) {
3892             if ( options.debug ) {
3893                 debugLine = 1;
3894                 emitcode("","C$%s$%d$%d$%d ==.",
3895                          ic->filename,ic->lineno,
3896                          ic->level,ic->block);
3897                 debugLine = 0;
3898             }
3899             emitcode(";","%s %d",ic->filename,ic->lineno);
3900             cln = ic->lineno ;
3901         }
3902         /* if the result is marked as
3903            spilt and rematerializable or code for
3904            this has already been generated then
3905            do nothing */
3906         if (resultRemat(ic) || ic->generated ) 
3907             continue ;
3908         
3909         /* depending on the operation */
3910         switch (ic->op) {
3911         case '!' :
3912             emitcode("", "; genNot");
3913             genNot(ic);
3914             break;
3915             
3916         case '~' :
3917             emitcode("", "; genCpl");
3918             genCpl(ic);
3919             break;
3920             
3921         case UNARYMINUS:
3922             emitcode("", "; genUminus");
3923             genUminus (ic);
3924             break;
3925             
3926         case IPUSH:
3927             emitcode("", "; genIpush");
3928             genIpush (ic);
3929             break;
3930             
3931         case IPOP:
3932             /* IPOP happens only when trying to restore a 
3933                spilt live range, if there is an ifx statement
3934                following this pop then the if statement might
3935                be using some of the registers being popped which
3936                would destory the contents of the register so
3937                we need to check for this condition and handle it */
3938             if (ic->next            && 
3939                 ic->next->op == IFX &&
3940                 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
3941                 emitcode("", "; genIfx");
3942                 genIfx (ic->next,ic);
3943             }
3944             else {
3945                 emitcode("", "; genIpop");
3946                 genIpop (ic);
3947             }
3948             break; 
3949             
3950         case CALL:
3951             emitcode("", "; genCall");
3952             genCall (ic);
3953             break;
3954             
3955         case PCALL:
3956             emitcode("", "; genPcall");
3957             genPcall (ic);
3958             break;
3959             
3960         case FUNCTION:
3961             emitcode("", "; genFunction");
3962             genFunction (ic);
3963             break;
3964             
3965         case ENDFUNCTION:
3966             emitcode("", "; genEndFunction");
3967             genEndFunction (ic);
3968             break;
3969             
3970         case RETURN:
3971             emitcode("", "; genRet");
3972             genRet (ic);
3973             break;
3974             
3975         case LABEL:
3976             emitcode("", "; genLabel");
3977             genLabel (ic);
3978             break;
3979             
3980         case GOTO:
3981             emitcode("", "; genGoto");
3982             genGoto (ic);
3983             break;
3984             
3985         case '+' :
3986             emitcode("", "; genPlus");
3987             genPlus (ic) ;
3988             break;
3989             
3990         case '-' :
3991             emitcode("", "; genMinus");
3992             genMinus (ic);
3993             break;
3994             
3995         case '*' :
3996             emitcode("", "; genMult");
3997             genMult (ic);
3998             break;
3999             
4000         case '/' :
4001             emitcode("", "; genDiv");
4002             genDiv (ic) ;
4003             break;
4004             
4005         case '%' :
4006             emitcode("", "; genMod");
4007             genMod (ic);
4008             break;
4009             
4010         case '>' :
4011             emitcode("", "; genCmpGt");
4012             genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));                 
4013             break;
4014             
4015         case '<' :
4016             emitcode("", "; genCmpLt");
4017             genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
4018             break;
4019             
4020         case LE_OP:
4021         case GE_OP:
4022         case NE_OP:
4023             
4024             /* note these two are xlated by algebraic equivalence
4025                during parsing SDCC.y */
4026             werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
4027                    "got '>=' or '<=' shouldn't have come here");
4028             break;      
4029             
4030         case EQ_OP:
4031             emitcode("", "; genCmpEq");
4032             genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
4033             break;          
4034             
4035         case AND_OP:
4036             emitcode("", "; genAndOp");
4037             genAndOp (ic);
4038             break;
4039             
4040         case OR_OP:
4041             emitcode("", "; genOrOp");
4042             genOrOp (ic);
4043             break;
4044             
4045         case '^' :
4046             emitcode("", "; genXor");
4047             genXor (ic,ifxForOp(IC_RESULT(ic),ic));
4048             break;
4049             
4050         case '|' :
4051             emitcode("", "; genOr");
4052             genOr (ic,ifxForOp(IC_RESULT(ic),ic));
4053             break;
4054             
4055         case BITWISEAND:
4056             emitcode("", "; genAnd");
4057             genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
4058             break;
4059             
4060         case INLINEASM:
4061             emitcode("", "; genInline");
4062             genInline (ic);
4063             break;
4064             
4065         case RRC:
4066             emitcode("", "; genRRC");
4067             genRRC (ic);
4068             break;
4069             
4070         case RLC:
4071             emitcode("", "; genRLC");
4072             genRLC (ic);
4073             break;
4074             
4075         case GETHBIT:
4076             emitcode("", "; genHBIT");
4077             assert(0);
4078             
4079         case LEFT_OP:
4080             emitcode("", "; genLeftShift");
4081             genLeftShift (ic);
4082             break;
4083             
4084         case RIGHT_OP:
4085             emitcode("", "; genRightShift");
4086             genRightShift (ic);
4087             break;
4088             
4089         case GET_VALUE_AT_ADDRESS:
4090             emitcode("", "; genPointerGet");
4091             genPointerGet(ic);
4092             break;
4093             
4094         case '=' :
4095
4096             if (POINTER_SET(ic)) {
4097                 emitcode("", "; genAssign (pointer)");
4098                 genPointerSet(ic);
4099             }
4100             else {
4101                 emitcode("", "; genAssign");
4102                 genAssign(ic);
4103             }
4104             break;
4105             
4106         case IFX:
4107             emitcode("", "; genIfx");
4108             genIfx (ic,NULL);
4109             break;
4110             
4111         case ADDRESS_OF:
4112             emitcode("", "; genAddrOf");
4113             genAddrOf (ic);
4114             break;
4115             
4116         case JUMPTABLE:
4117             emitcode("", "; genJumpTab");
4118             genJumpTab (ic);
4119             break;
4120             
4121         case CAST:
4122             emitcode("", "; genCast");
4123             genCast (ic);
4124             break;
4125             
4126         case RECEIVE:
4127             emitcode("", "; genReceive");
4128             genReceive(ic);
4129             break;
4130             
4131         case SEND:
4132             emitcode("", "; addSet");
4133             addSet(&sendSet,ic);
4134             break;
4135
4136         default :
4137             ic = ic;
4138             /*      piCode(ic,stdout); */
4139             
4140         }
4141     }
4142     
4143
4144     /* now we are ready to call the 
4145        peep hole optimizer */
4146     if (!options.nopeep)
4147         peepHole (&lineHead);
4148
4149     /* now do the actual printing */
4150     printLine (lineHead,codeOutFile);
4151     return;
4152 }