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