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