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